/****************************************************************************** * Copyright (c) 2005 BEA Systems, Inc. * 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: * Konstantin Komissarchik - initial API and implementation ******************************************************************************/ package org.eclipse.jst.j2ee.project.facet; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.jdt.core.IClasspathAttribute; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jst.common.project.facet.core.ClasspathHelper; import org.eclipse.jst.common.project.facet.core.IClasspathProvider; import org.eclipse.jst.common.project.facet.core.internal.FacetCorePlugin; import org.eclipse.wst.common.componentcore.ComponentCore; import org.eclipse.wst.common.componentcore.resources.IVirtualComponent; import org.eclipse.wst.common.componentcore.resources.IVirtualReference; import org.eclipse.wst.common.project.facet.core.IDelegate; import org.eclipse.wst.common.project.facet.core.IFacetedProject; import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; import org.eclipse.wst.common.project.facet.core.IRuntimeChangedEvent; import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager; import org.eclipse.wst.common.project.facet.core.runtime.IRuntime; import org.osgi.service.prefs.BackingStoreException; /** * @author <a href="mailto:kosta@bea.com">Konstantin Komissarchik</a> */ public final class J2EEFacetRuntimeChangedDelegate implements IDelegate { public static final String LEGACY_METADATA_FILE_NAME = ".settings/org.eclipse.jst.common.project.facet.core.prefs"; //$NON-NLS-1$ private static final String OWNER_PROJECT_FACETS_ATTR = "owner.project.facets"; //$NON-NLS-1$ public void execute( final IProject project, final IProjectFacetVersion fv, final Object cfg, final IProgressMonitor monitor ) throws CoreException { if( monitor != null ) { monitor.beginTask( "", 11 ); //$NON-NLS-1$ } try { IRuntimeChangedEvent event = (IRuntimeChangedEvent)cfg; // Using our remove Utility to first check for missing preferences removeClasspathEntries( project, fv, event.getOldRuntime()); if( ! ClasspathHelper.addClasspathEntries( project, fv ) ) { // TODO: Support the no runtime case. // ClasspathHelper.addClasspathEntries( project, fv, <something> ); } if( monitor != null ) { monitor.worked( 1 ); } // Cascade this runtime change to projects referenced by this project // Compile the list of projects referenced by this project. final Set<IProject> childProjects = new HashSet<IProject>(); final IVirtualComponent projectVC = ComponentCore.createComponent( project ); Map<String, Object> options = new HashMap<String, Object>(); options.put(IVirtualComponent.REQUESTED_REFERENCE_TYPE, IVirtualComponent.HARD_REFERENCES); final IVirtualReference[] vrefs = projectVC.getReferences(options); for( int i = 0; i < vrefs.length; i++ ) { final IVirtualReference vref = vrefs[ i ]; final IVirtualComponent vc = vref.getReferencedComponent(); childProjects.add( vc.getProject() ); } if( monitor != null ) { monitor.worked( 1 ); } // Attempt to change the runtime for each of the referenced projects. updateProjectRuntime( project, childProjects, submon( monitor, 9 ) ); } finally { if( monitor != null ) { monitor.done(); } } } private void removeClasspathEntries(IProject project, IProjectFacetVersion fv, IRuntime oldRuntime) throws CoreException { IJavaProject jproj = JavaCore.create(project); List cp = getClasspath(jproj); boolean hasPrefs = hasClasspathPreferencesNode(project); // In the case where no prefs exists... make sure the entries of the // oldRuntime are removed before continuing if (!hasPrefs) { removeOnlyCPEntries(project, fv, jproj, cp, oldRuntime); } else ClasspathHelper.removeClasspathEntries(project, fv); } private boolean hasClasspathPreferencesNode(IProject project) { IProject pj = project.getProject(); IFile legacyMetadataFile = pj.getFile( LEGACY_METADATA_FILE_NAME ); // First check if file exists if( legacyMetadataFile.exists() ) { ProjectScope scope = new ProjectScope(project); IEclipsePreferences pluginRoot = scope.getNode(FacetCorePlugin.PLUGIN_ID); try { return pluginRoot.nodeExists("classpath.helper"); //$NON-NLS-1$ } catch (BackingStoreException e) { org.eclipse.jst.j2ee.internal.plugin.J2EEPlugin.logError(e); } } //Now check classpath entries for new attributes IJavaProject jproj = JavaCore.create( project ); return hasClasspathPreferencesNode(jproj); } private boolean hasClasspathPreferencesNode(IJavaProject jproj) { boolean attributeFound = false; IClasspathEntry[] entries = null; try { entries = jproj.getRawClasspath(); } catch (JavaModelException e) { org.eclipse.jst.j2ee.internal.plugin.J2EEPlugin.logError(e); } int i = 0; if (entries != null) { while (!attributeFound && i < entries.length) { IClasspathEntry cpe = entries[i]; attributeFound = hasOwnerAttribute( cpe ); i++; } } return attributeFound; } private boolean hasOwnerAttribute(IClasspathEntry cpe) { if( cpe != null ) { for( IClasspathAttribute attr : cpe.getExtraAttributes() ) { if( attr.getName().equals( OWNER_PROJECT_FACETS_ATTR ) ) return true; } } return false; } private void removeOnlyCPEntries(final IProject project, final IProjectFacetVersion fv, final IJavaProject jproj, final List cp, IRuntime oldRuntime) throws CoreException { IFacetedProject fproj = ProjectFacetsManager.create(project); IRuntime runtime = (oldRuntime != null) ? oldRuntime : fproj.getPrimaryRuntime(); if (runtime != null) { IClasspathProvider cpprov = (IClasspathProvider) runtime.getAdapter(IClasspathProvider.class); List cpentries = cpprov.getClasspathEntries(fv); boolean realCPChanged = false; if (cpentries != null) { for (Iterator itr = cpentries.iterator(); itr.hasNext();) { IClasspathEntry cpentry = (IClasspathEntry) itr.next(); IPath path = cpentry.getPath(); boolean contains = cp.contains(cpentry); if (contains) { for (Iterator itr2 = cp.iterator(); itr2.hasNext();) { final IClasspathEntry realEntry = (IClasspathEntry) itr2.next(); if (realEntry.getPath().equals(path)) { itr2.remove(); realCPChanged = true; break; } } } } } if (realCPChanged) { IClasspathEntry[] newcp = (IClasspathEntry[]) cp.toArray(new IClasspathEntry[cp.size()]); jproj.setRawClasspath(newcp, null); } } } private List getClasspath(final IJavaProject jproj) throws CoreException { ArrayList list = new ArrayList(); IClasspathEntry[] cp = jproj.getRawClasspath(); for (int i = 0; i < cp.length; i++) { list.add(cp[i]); } return list; } private static IProgressMonitor submon( final IProgressMonitor parent, final int ticks ) { return ( parent == null ? null : new SubProgressMonitor( parent, ticks ) ); } public static void updateProjectRuntime( final IProject project, final IProject childProject, final IProgressMonitor monitor ) throws CoreException { if( monitor != null ) { monitor.beginTask( "", 1 ); //$NON-NLS-1$ } try { final IFacetedProject facetedProject = ProjectFacetsManager.create( project ); final IRuntime projectRuntime = facetedProject.getRuntime(); final IFacetedProject childFacetedProject = ProjectFacetsManager.create( childProject ); if( childFacetedProject != null && ! equals(projectRuntime, childFacetedProject.getRuntime())) { boolean supports = true; if( projectRuntime != null ) { for( Iterator itr = childFacetedProject.getProjectFacets().iterator(); itr.hasNext(); ) { final IProjectFacetVersion fver = (IProjectFacetVersion) itr.next(); if(!projectRuntime.supports(fver)) { supports = false; break; } } } if( supports ) { childFacetedProject.setRuntime(projectRuntime, submon( monitor, 1 ) ); } } } finally { if( monitor != null ) { monitor.done(); } } } public static void updateProjectRuntime( final IProject project, final Set<IProject> childProjects, final IProgressMonitor monitor ) throws CoreException { if( monitor != null ) { monitor.beginTask( "", childProjects.size() ); //$NON-NLS-1$ } try { for(final IProject childProject : childProjects) { updateProjectRuntime( project, childProject, submon( monitor, 1 ) ); } } finally { if( monitor != null ) { monitor.done(); } } } private static boolean equals( final Object obj1, final Object obj2 ) { if( obj1 == obj2 ) { return true; } else if( obj1 == null || obj2 == null ) { return false; } else { return obj1.equals( obj2 ); } } }