=========================================================================== 14.1.1 Declaring a builder =========================================================================== =========================================================================== 14.1.2 IncrementalProjectBuilder =========================================================================== package com.qualityeclipse.favorites.builder; import java.util.*; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import com.qualityeclipse.favorites.*; public class PropertiesFileAuditor extends IncrementalProjectBuilder { protected IProject[] build( int kind, Map args, IProgressMonitor monitor) throws CoreException { if (shouldAudit(kind)) auditPluginManifest(monitor); return null; } … other methods discussed later inserted here … } =========================================================================== private boolean shouldAudit(int kind) { if (kind == FULL_BUILD) return true; IResourceDelta delta = getDelta(getProject()); if (delta == null) return false; IResourceDelta[] children = delta.getAffectedChildren(); for (int i = 0; i < children.length; i++) { IResourceDelta child = children[i]; String fileName = child.getProjectRelativePath().lastSegment(); if (fileName.equals(“plugin.xml”) || fileName.equals(“plugin.properties”)) return true; } return false; } =========================================================================== private void auditPluginManifest(IProgressMonitor monitor) { monitor.beginTask(“Audit plugin manifest”, 4); if (checkCancel(monitor)) return; Map pluginKeys = scanPlugin( getProject().getFile(“plugin.xml”)); monitor.worked(1); if (checkCancel(monitor)) return; Map propertyKeys = scanProperties( getProject().getFile(“plugin.properties”)); monitor.worked(1); if (checkCancel(monitor)) return; Iterator iter = pluginKeys.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); if (!propertyKeys.containsKey(entry.getKey())) reportProblem( “Missing property key”, ((Location) entry.getValue()), 1, true); } monitor.worked(1); if (checkCancel(monitor)) return; iter = propertyKeys.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); if (!pluginKeys.containsKey(entry.getKey())) reportProblem( “Unused property key”, ((Location) entry.getValue()), 2, false); } monitor.done(); } private boolean checkCancel(IProgressMonitor monitor) { if (monitor.isCanceled()) { // Discard build state if necessary. throw new OperationCanceledException(); } if (isInterrupted()) { // Discard build state if necessary. return true; } return false; } =========================================================================== private Map scanPlugin(IFile file) { Map keys = new HashMap(); String content = readFile(file); int start = 0; while (true) { start = content.indexOf(“\”%”, start); if (start < 0) break; int end = content.indexOf(‘“‘, start + 2); if (end < 0) break; Location loc = new Location(); loc.file = file; loc.key = content.substring(start + 2, end); loc.charStart = start + 1; loc.charEnd = end; keys.put(loc.key, loc); start = end + 1; } return keys; } private Map scanProperties(IFile file) { Map keys = new HashMap(); String content = readFile(file); int end = 0; while (true) { end = content.indexOf(‘=‘, end); if (end < 0) break; int start = end—1; while (start >= 0) { char ch = content.charAt(start); if (ch == ‘\r’ || ch == ‘\n’) break; start--; } start++; String found = content.substring(start, end).trim(); if (found.length() == 0 || found.charAt(0) == ‘#’ || found.indexOf(‘=‘) != -1) continue; Location loc = new Location(); loc.file = file; loc.key = found; loc.charStart = start; loc.charEnd = end; keys.put(loc.key, loc); end++; } return keys; } =========================================================================== private String readFile(IFile file) { if (!file.exists()) return ““; InputStream stream = null; try { stream = file.getContents(); Reader reader = new BufferedReader( new InputStreamReader(stream)); StringBuffer result = new StringBuffer(2048); char[] buf = new char[2048]; while (true) { int count = reader.read(buf); if (count < 0) break; result.append(buf, 0, count); } return result.toString(); } catch (Exception e) { FavoritesLog.logError(e); return ““; } finally { try { if (stream != null) stream.close(); } catch (IOException e) { FavoritesLog.logError(e); return ““; } } } =========================================================================== private void reportProblem( String msg, Location loc, int violation, boolean isError) { System.out.println( (isError ? “ERROR: “ : “WARNING: “) + msg + “ \”“ + loc.key + “\” in “ + loc.file.getFullPath()); } =========================================================================== private class Location { IFile file; String key; int charStart; int charEnd; } =========================================================================== 14.1.4 Associating a builder with a project =========================================================================== public static final String BUILDER_ID = FavoritesPlugin.getDefault().getDescriptor() .getUniqueIdentifier() + “.propertiesFileAuditor”; public static void addBuilderToProject(IProject project) { // Cannot modify closed projects. if (!project.isOpen()) return; // Get the description. IProjectDescription description; try { description = project.getDescription(); } catch (CoreException e) { FavoritesLog.logError(e); return; } // Look for builder already associated. ICommand[] cmds = description.getBuildSpec(); for (int j = 0; j < cmds.length; j++) if (cmds[j].getBuilderName().equals(BUILDER_ID)) return; // Associate builder with project. ICommand newCmd = description.newCommand(); newCmd.setBuilderName(BUILDER_ID); List newCmds = new ArrayList(); newCmds.addAll(Arrays.asList(cmds)); newCmds.add(newCmd); description.setBuildSpec( (ICommand[]) newCmds.toArray( new ICommand[newCmds.size()])); try { project.setDescription(description, null); } catch (CoreException e) { FavoritesLog.logError(e); } } =========================================================================== com.qualityeclipse.favorites.propertiesFileAuditor =========================================================================== public static void removeBuilderFromProject(IProject project) { // Cannot modify closed projects. if (!project.isOpen()) return; // Get the description. IProjectDescription description; try { description = project.getDescription(); } catch (CoreException e) { FavoritesLog.logError(e); return; } // Look for builder. int index = -1; ICommand[] cmds = description.getBuildSpec(); for (int j = 0; j < cmds.length; j++) { if (cmds[j].getBuilderName().equals(BUILDER_ID)) { index = j; break; } } if (index == -1) return; // Remove builder from project. List newCmds = new ArrayList(); newCmds.addAll(Arrays.asList(cmds)); newCmds.remove(index); description.setBuildSpec( (ICommand[]) newCmds.toArray( new ICommand[newCmds.size()])); try { project.setDescription(description, null); } catch (CoreException e) { FavoritesLog.logError(e); } } =========================================================================== 14.2.1 Marker types =========================================================================== =========================================================================== private static final String MARKER_ID = FavoritesPlugin.getDefault().getDescriptor() .getUniqueIdentifier() + “.auditmarker”; =========================================================================== 14.2.2 Creating and deleting markers =========================================================================== private void auditPluginManifest(IProgressMonitor monitor) { monitor.beginTask(“Audit plugin manifest”, 4); if (!deleteAuditMarkers(getProject())) return; if (checkCancel(monitor)) return; … etc … } =========================================================================== public static boolean deleteAuditMarkers(IProject project) { try { project.deleteMarkers( MARKER_ID, false, IResource.DEPTH_INFINITE); return true; } catch (CoreException e) { FavoritesLog.logError(e); return false; } } =========================================================================== public static final String KEY = “key”; public static final String VIOLATION = “violation”; private void reportProblem( String msg, Location loc, int violation, boolean isError) { try { IMarker marker = loc.file.createMarker(MARKER_ID); marker.setAttribute( IMarker.MESSAGE, msg + “: “ + loc.key); marker.setAttribute( IMarker.CHAR_START, loc.charStart); marker.setAttribute( IMarker.CHAR_END, loc.charEnd); marker.setAttribute( IMarker.SEVERITY, isError ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING); marker.setAttribute(KEY, loc.key); marker.setAttribute(VIOLATION, violation); } catch (CoreException e) { FavoritesLog.logError(e); return; } } =========================================================================== protected IProject[] build( int kind, Map args, IProgressMonitor monitor) throws CoreException { if (shouldAudit(kind)) { ResourcesPlugin.getWorkspace().run( new IWorkspaceRunnable() { public void run(IProgressMonitor monitor) throws CoreException { auditPluginManifest(monitor); } }, monitor ); } return null; } =========================================================================== 14.2.3 Marker attributes =========================================================================== =========================================================================== 14.2.4 Marker resolution—quick fix =========================================================================== =========================================================================== package com.qualityeclipse.favorites.builder; import java.util.*; import org.eclipse.core.resources.*; import org.eclipse.ui.*; public class ViolationResolutionGenerator implements IMarkerResolutionGenerator2 { public boolean hasResolutions(IMarker marker) { switch (getViolation(marker)) { case 1 : return true; case 2 : return true; default : return false; } } public IMarkerResolution[] getResolutions(IMarker marker){ List resolutions = new ArrayList(); switch (getViolation(marker)) { case 1 : resolutions.add( new CreatePropertyKeyResolution()); break; case 2 : resolutions.add( new DeletePropertyKeyResolution()); resolutions.add( new CommentPropertyKeyResolution()); break; default : break; } return (IMarkerResolution[]) resolutions.toArray( new IMarkerResolution[resolutions.size()]); } private int getViolation(IMarker marker) { return marker.getAttribute( PropertiesFileAuditor.VIOLATION, 0); } } =========================================================================== package com.qualityeclipse.favorites.builder; import java.io.*; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.eclipse.jface.text.*; import org.eclipse.swt.graphics.*; import org.eclipse.ui.*; import org.eclipse.ui.ide.*; import org.eclipse.ui.part.*; import org.eclipse.ui.texteditor.*; import com.qualityeclipse.favorites.*; public class CreatePropertyKeyResolution implements IMarkerResolution2 { public String getDescription() { return “Append a new property key/value pair” + “ to the plugin.properties file”; } public Image getImage() { return null; } public String getLabel() { return “Create a new property key”; } public void run(IMarker marker) { // Get the corresponding plugin.properties. IFile file = marker.getResource().getParent().getFile( new Path(“plugin.properties”)); if (!file.exists()) { ByteArrayInputStream stream = new ByteArrayInputStream(new byte[] {}); try { file.create(stream, false, null); } catch (CoreException e) { FavoritesLog.logError(e); return; } } // Open or activate the editor. IWorkbenchPage page = PlatformUI .getWorkbench() .getActiveWorkbenchWindow() .getActivePage(); IEditorPart part; try { part = IDE.openEditor(page, file, true); } catch (PartInitException e) { FavoritesLog.logError(e); return; } // Get the editor’s document. if (!(part instanceof ITextEditor)) return; ITextEditor editor = (ITextEditor) part; IDocument doc = editor.getDocumentProvider().getDocument( new FileEditorInput(file)); // Determine the text to be added. String key; try { key = (String) marker.getAttribute( PropertiesFileAuditor.KEY); } catch (CoreException e) { FavoritesLog.logError(e); return; } String text = key + “=Value for “ + key; // If necessary, add a newline. int index = doc.getLength(); if (index > 0) { char ch; try { ch = doc.getChar(index—1); } catch (BadLocationException e) { FavoritesLog.logError(e); return; } if (ch != ‘\r’ || ch != ‘\n’) text = System.getProperty(“line.separator”) + text; } // Append the new text. try { doc.replace(index, 0, text); } catch (BadLocationException e) { FavoritesLog.logError(e); return; } // Select the value so the user can type. index += text.indexOf(‘=‘) + 1; editor.selectAndReveal( index, doc.getLength()—index); } } =========================================================================== 14.2.5 Finding markers =========================================================================== IMarker[] markers; try { markers = myFolder.findMarkers( IMarker.PROBLEM, true, IResource.DEPTH_INFINITE); } catch (CoreException e) { // Log the exception and bail out. } =========================================================================== 14.3.1 Declaring a nature =========================================================================== =========================================================================== 14.3.2 Associating builders and natures =========================================================================== =========================================================================== 14.3.3 IProjectNature =========================================================================== =========================================================================== package com.qualityeclipse.favorites.builder; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; public class PropertiesAuditorNature implements IProjectNature { private IProject project; public IProject getProject() { return project; } public void setProject(IProject project) { this.project = project; } public void configure() throws CoreException { PropertiesFileAuditor.addBuilderToProject(project); new Job(“Properties File Audit”) { protected IStatus run(IProgressMonitor monitor) { try { project.build( PropertiesFileAuditor.FULL_BUILD, PropertiesFileAuditor.BUILDER_ID, null, monitor); } catch (CoreException e) { FavoritesLog.logError(e); } return Status.OK_STATUS; } }.schedule(); } public void deconfigure() throws CoreException { PropertiesFileAuditor .removeBuilderFromProject(project); PropertiesFileAuditor.deleteAuditMarkers(project); } } =========================================================================== 14.3.4 Required natures =========================================================================== =========================================================================== 14.3.5 Conflicting natures =========================================================================== =========================================================================== 14.3.6 Nature image =========================================================================== =========================================================================== 14.3.7 Associating a nature with a project =========================================================================== =========================================================================== package com.qualityeclipse.favorites.actions; import java.util.*; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.eclipse.jface.action.*; import org.eclipse.jface.viewers.*; import org.eclipse.ui.*; import com.qualityeclipse.favorites.*; public class ToggleProjectNatureActionDelegate implements IWorkbenchWindowActionDelegate { private static final String NATURE_ID = FavoritesPlugin.getDefault().getDescriptor() .getUniqueIdentifier() + “.propertiesAuditor”; private ISelection selection; public void init(IWorkbenchWindow window) { // Ignored. } public void selectionChanged( IAction action, ISelection selection) { this.selection = selection; } public void run(IAction action) { if (!(selection instanceof IStructuredSelection)) return; Iterator iter = ((IStructuredSelection) selection).iterator(); while (iter.hasNext()) { Object element = iter.next(); if (!(element instanceof IProject)) continue; IProject project = (IProject) element; // Cannot modify closed projects. if (!project.isOpen()) continue; // Get the description. IProjectDescription description; try { description = project.getDescription(); } catch (CoreException e) { FavoritesLog.logError(e); continue; } // Toggle the nature. List newIds = new ArrayList(); newIds.addAll( Arrays.asList(description.getNatureIds())); int index = newIds.indexOf(NATURE_ID); if (index == -1) newIds.add(NATURE_ID); else newIds.remove(index); description.setNatureIds( (String[]) newIds.toArray( new String[newIds.size()])); // Save the description. try { project.setDescription(description, null); } catch (CoreException e) { FavoritesLog.logError(e); } } } public void dispose() { } }