/******************************************************************************* * Copyright (c) 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 * IBM Research *******************************************************************************/ package com.ibm.research.tagging.java; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.ui.texteditor.MarkerUtilities; import com.ibm.research.tagging.core.ITag; import com.ibm.research.tagging.core.TagCorePlugin; import com.ibm.research.tagging.java.extractor.WaypointDefinitionExtractor; import com.ibm.research.tagging.java.markers.WaypointMarkerParser; import com.ibm.research.tagging.java.markers.WaypointMarkerValidator; import com.ibm.research.tagging.java.parser.IJavaWaypointInfo; import com.ibm.research.tagging.java.parser.IJavaWaypointParser; import com.ibm.research.tagging.java.parser.JavaWaypointParserFactory; import com.ibm.research.tagging.java.parser.JavaWaypointParserUtilities; import com.ibm.research.tagging.java.refactoring.DocumentReadSession; public class ModifiedFileSynchronizer { public void lockAndSynchronizeWithModel(IFile file) { //Lock the document for the duration DocumentReadSession session = new DocumentReadSession(file); session.begin(); try { synchronizeWithModel(file, session.getDocument()); } finally { session.end(); } } public void synchronizeWithModel(IFile file, IDocument document) { List<IRegion> newWaypointRegions = new ArrayList<IRegion>(); // Get markers IMarker markerArray[] = getMarkers(file); //Get invalidated markers List<IMarker> invalidatedMarkers = getInvalidatedMarkers(file,markerArray); // Get the waypoint regions IRegion[] waypointRegions = WaypointDefinitionExtractor.getWaypointRegions(document); // Match the waypoint regions with the existing waypoint markers for(IRegion region : waypointRegions) { boolean matched = false; for(IMarker marker : markerArray) { int offset = MarkerUtilities.getCharStart(marker); int length = MarkerUtilities.getCharEnd(marker) - offset; if(region.getOffset() == offset) { matched = true; break; } } if(!matched) newWaypointRegions.add(region); } removeDeletedWaypoints(file); List<IMarker> deletedMarkers = new ArrayList<IMarker>(); // Process the invalidated markers, an invalidated marker was either deleted or modified for(IMarker marker : invalidatedMarkers) { boolean markerMatched = false; int offset = MarkerUtilities.getCharStart(marker); // look for a matching region for this invalid waypoint for(IRegion region : waypointRegions) { // We ASSUME that this is the matching region if(region.getOffset() == offset) { markerMatched = true; updateWaypointWithRegion(region,document,marker); } } // We can assume that this waypoint was deleted :( But the // eclipse marker stuff is too dumb to realise if(!markerMatched) { deletedMarkers.add(marker); } } // Remove the deleted markers and waypoints for(IMarker marker : deletedMarkers) { // Get the waypoint JavaWaypoint waypoint = (JavaWaypoint)TagCorePlugin.getDefault().getTagCore().getWaypointModel().getWaypoint(Long.toString(marker.getId())); JavaWaypointPlugin.getDefault().removeWaypoint(waypoint); try { marker.delete(); } catch (CoreException e) { e.printStackTrace(); } } // Create the new waypoints for(IRegion region : newWaypointRegions) { IMarker marker = WaypointMarkerFactory.createMarker(file, document, region); if(marker != null) { WaypointMarkerParser parser = new WaypointMarkerParser(); IJavaWaypointInfo info; try { info = parser.parse(marker); } catch (Exception e) { e.printStackTrace(); continue; } String author = JavaWaypointParserUtilities.getAuthor(info); Date date = JavaWaypointParserUtilities.getDate(info); JavaWaypoint waypoint = new JavaWaypoint(marker,info.getDescription(),author,date); // Always add java waypoints via the proxy JavaWaypointPlugin.getDefault().addWaypoint(waypoint); for(String tagName : info.getTags()) { ITag tag = TagCorePlugin.getDefault().getTagCore().getTagModel().addTag(tagName); waypoint.addTag(tag); } } } } private void updateWaypointWithRegion(IRegion region,IDocument document, IMarker marker) { String waypointDefinition = null; try { waypointDefinition = document.get(region.getOffset(), region.getLength()); } catch (BadLocationException e) { e.printStackTrace(); } try { // Update the marker fields marker.setAttribute(IMarker.MESSAGE, waypointDefinition); marker.setAttribute(IMarker.CHAR_START, region.getOffset()); marker.setAttribute(IMarker.CHAR_END, region.getOffset() + region.getLength()); } catch (CoreException e) { e.printStackTrace(); } // Get the waypoint JavaWaypoint waypoint = (JavaWaypoint)TagCorePlugin.getDefault().getTagCore().getWaypointModel().getWaypoint(Long.toString(marker.getId())); // parser the waypoint and update IJavaWaypointParser parser = JavaWaypointParserFactory.createParser(); IJavaWaypointInfo info = null; try { info = parser.parse(waypointDefinition); } catch (Exception e) { // whoops looks like this waypoint was actually deleted! JavaWaypointPlugin.getDefault().removeWaypoint(waypoint); e.printStackTrace(); return; } if(!waypoint.getDescription().equals(info.getDescription())) waypoint.setDescription(info.getDescription()); String author = JavaWaypointParserUtilities.getAuthor(info); if(!waypoint.getAuthor().equals(author)) waypoint.setAuthor(author); Date date = JavaWaypointParserUtilities.getDate(info); waypoint.setDate(date); ITag[] tags = waypoint.getTags(); String[] tagNames = info.getTags(); for(String tagName : tagNames) { boolean matched = false; for(ITag tag : tags) { if(tagName.equals(tag.getName())) matched = true; } if(!matched) waypoint.addTag(TagCorePlugin.getDefault().getTagCore().getTagModel().addTag(tagName)); } for(ITag tag : tags) { boolean matched = false; for(String tagName : tagNames) { if(tagName.equals(tag.getName())) matched = true; } if(!matched) waypoint.removeTag(tag); } } private void removeDeletedWaypoints(IFile file) { // Remove any deleted waypoints List<JavaWaypoint> existingWaypoints = JavaWaypointPlugin.getDefault().get(file); List<JavaWaypoint> deletedWaypoints = new ArrayList<JavaWaypoint>(); if(existingWaypoints != null) { for(JavaWaypoint jw : existingWaypoints) { if(!jw.exists()) deletedWaypoints.add(jw); } } for(JavaWaypoint w : deletedWaypoints) { JavaWaypointPlugin.getDefault().removeWaypoint(w); } } private IMarker[] getMarkers(IFile file) { try { return file.findMarkers(JavaWaypoint.MARKER_ID, false, IResource.DEPTH_ZERO); } catch (CoreException e) { e.printStackTrace(); } return new IMarker[0]; } private List<IMarker> getInvalidatedMarkers(IFile file, IMarker[] markerArray) { List<IMarker> invalidatedMarkers = new ArrayList<IMarker>(); WaypointMarkerValidator validator = new WaypointMarkerValidator(file); for(IMarker marker : markerArray) { if(!validator.isValid(marker)) invalidatedMarkers.add(marker); } return invalidatedMarkers; } }