===========================================================================
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() {
}
}