/******************************************************************************* * Copyright (c) 2001, 2006 IBM Corporation and others. * 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jem.internal.beaninfo.adapters; /* */ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.*; import org.eclipse.jem.workbench.utility.JavaModelListener; /** * This class listens for changes to the java model and flushs the * appropriate class introspection. */ public class BeaninfoModelSynchronizer extends JavaModelListener { protected BeaninfoAdapterFactory fAdapterFactory; protected IJavaProject fProject; // The project this listener is opened on. private static final IPath BEANINFOCONFIG_PATH = new Path(BeaninfoNature.P_BEANINFO_SEARCH_PATH); //$NON-NLS-1$ public BeaninfoModelSynchronizer(BeaninfoAdapterFactory aFactory, IJavaProject aProject) { super(ElementChangedEvent.POST_CHANGE); fAdapterFactory = aFactory; fProject = aProject; } /* (non-Javadoc) * @see org.eclipse.jem.internal.adapters.jdom.JavaModelListener#getJavaProject() */ protected IJavaProject getJavaProject() { return fProject; } /* (non-Javadoc) * @see org.eclipse.jem.internal.adapters.jdom.JavaModelListener#isAlsoClasspathChange(org.eclipse.core.runtime.IPath) */ protected boolean isAlsoClasspathChange(IPath path) { return path.equals(BEANINFOCONFIG_PATH); } /** * Stop the synchronizer from listening to any more changes. */ public void stopSynchronizer(boolean clearResults) { JavaCore.removeElementChangedListener(this); getAdapterFactory().closeAll(clearResults); } public BeaninfoAdapterFactory getAdapterFactory() { return fAdapterFactory; } protected void processJavaElementChanged(IJavaProject element, IJavaElementDelta delta) { if (isInClasspath(element)) { if (delta.getKind() == IJavaElementDelta.REMOVED || delta.getKind() == IJavaElementDelta.ADDED) { // Don't need to do anything for delete/close/add/open of main project because there is much more that needs to // be done by BeaninfoNature on project close/delete, so nature listens for this and does the appropriate cleanup. if (!element.equals(fProject)) { // However, all other projects are required projects and if they are deleted/closed/added/opened when need to do // a full flush because we don't know any of the state, whether they are still there or not. getAdapterFactory().markAllStale(); } return; } else if (isClasspathResourceChange(delta)) { getAdapterFactory().markAllStale(); // The .classpath file (or .beaninfoconfig) itself in SOME DEPENDENT PROJECT has changed. return; } processChildren(element, delta); } } /** * Handle the change for a single element, children will be handled separately. * If a working copy, then ignore it because we don't care about changes until * they are committed. Else, if the CU has changed content then mark all of the * types in this CU (such as inner classes) as stale. * If it is not a content change then process the children. */ protected void processJavaElementChanged(ICompilationUnit element, IJavaElementDelta delta) { switch (delta.getKind()) { case IJavaElementDelta.CHANGED : // A file save had occurred. It doesn't matter if currently working copy or not. // It means something has changed to the file on disk, but don't know what. if ((delta.getFlags() & IJavaElementDelta.F_PRIMARY_RESOURCE) != 0) { getAdapterFactory().markStaleIntrospectionPlusInner(getFullNameFromElement(element), false); // Flush everything, including inner classes. } break; case IJavaElementDelta.ADDED: case IJavaElementDelta.REMOVED: // Need to know for add because we optimize the beaninfo such that once found as undefined, it won't // introspect again until we mark it stale. So we need to mark it stale to refresh it. // It doesn't matter if totally removed or just moved somewhere else, we will clear out // adapter because there could be a rename which would be a different class. // Currently the element is already deleted or added and there is no way to find the types in the unit to flush. // So instead we ask factory to flush all it any that start with it plus for inner classes. getAdapterFactory().markStaleIntrospectionPlusInner(getFullNameFromElement(element), true); // Flush everything, including inner classes. break; } } /** * Handle the change for a single element, children will be handled separately. */ protected void processJavaElementChanged(IClassFile element, IJavaElementDelta delta) { if (delta.getKind() == IJavaElementDelta.REMOVED) { // It doesn't matter if totally removed or just moved somewhere else, we will clear out and remove the // adapter because there could be a rename which would be a different class. // Currently the element is already deleted and there is no way to find the types in the unit to remove. // So instead we ask factory to remove all it any that start with it plus for inner classes. getAdapterFactory().markStaleIntrospectionPlusInner(getFullNameFromElement(element), true); return; // Since the classfile was removed we don't need to process the children (actually the children list will be empty } IJavaElementDelta[] children = delta.getAffectedChildren(); for (int ii = 0; ii < children.length; ii++) { processDelta(children[ii]); } } protected String getFullNameFromElement(IJavaElement element) { String name = element.getElementName(); if (!(element instanceof ICompilationUnit || element instanceof IClassFile)) return name; // Shouldn't be here // remove extension. int periodNdx = name.lastIndexOf('.'); if (periodNdx == -1) return name; // Shouldn't be here. There should be an extension String typeName = null; String parentName = element.getParent().getElementName(); if (parentName == null || parentName.length() == 0) typeName = name.substring(0, periodNdx); // In default package else typeName = parentName + "." + name.substring(0, periodNdx); //$NON-NLS-1$ return typeName; } /** * Handle the change for a single element, children will be handled separately. * If the classpath has changed, mark all as stale because we don't know what * has changed. Things that were in the path may no longer be in the path, or * the order was changed, which could affect the introspection. */ protected void processJavaElementChanged(IPackageFragmentRoot element, IJavaElementDelta delta) { if (isClassPathChange(delta)) fAdapterFactory.markAllStale(); else super.processJavaElementChanged(element, delta); } protected void processJavaElementChanged(IPackageFragment element, IJavaElementDelta delta) { switch (delta.getKind()) { case IJavaElementDelta.ADDED: // Even though added there is possibility that package exists in other root but this // one may now take priority, so we will clear the package anyway. case IJavaElementDelta.REMOVED: fAdapterFactory.markPackageStale(element.getElementName()); break; default : super.processJavaElementChanged(element, delta); } } /** * Handle the change for a single element, children will be handled separately. * Something about the type has changed. If it was removed (not a move), then close the * adapter too. */ protected void processJavaElementChanged(IType element, IJavaElementDelta delta) { if (delta.getKind() == IJavaElementDelta.REMOVED) { // Close it out. Doesn't matter if moved_to, that would be a rename which requires brand new class. // We can't actually get rid of the beaninfo adapter because it may be asked for again // just to see if not defined. It may also come back later and we want to know about // it to recycle the vm. getAdapterFactory().markStaleIntrospection(element.getFullyQualifiedName(), true); } else getAdapterFactory().markStaleIntrospection(element.getFullyQualifiedName(), false); // Just mark it stale processChildren(element, delta); } public String toString() { return super.toString()+" "+fProject.getElementName(); //$NON-NLS-1$ } }