blob: 9124c8237c9f252d627c93c692735dec84d50787 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 Martin Reiterer.
* 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:
* Martin Reiterer - initial API and implementation
******************************************************************************/
package org.eclipse.babel.tapiji.tools.core.ui.builder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.babel.core.configuration.ConfigurationManager;
import org.eclipse.babel.core.configuration.IConfiguration;
import org.eclipse.babel.tapiji.tools.core.Logger;
import org.eclipse.babel.tapiji.tools.core.extensions.ILocation;
import org.eclipse.babel.tapiji.tools.core.extensions.MarkerConstants;
import org.eclipse.babel.tapiji.tools.core.model.exception.NoSuchResourceAuditorException;
import org.eclipse.babel.tapiji.tools.core.ui.ResourceBundleManager;
import org.eclipse.babel.tapiji.tools.core.ui.analyzer.ResourceFinder;
import org.eclipse.babel.tapiji.tools.core.ui.extensions.I18nAuditor;
import org.eclipse.babel.tapiji.tools.core.ui.extensions.I18nRBAuditor;
import org.eclipse.babel.tapiji.tools.core.ui.extensions.I18nResourceAuditor;
import org.eclipse.babel.tapiji.tools.core.ui.utils.EditorUtils;
import org.eclipse.babel.tapiji.tools.core.ui.utils.RBFileUtils;
import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
public class I18nBuilder extends IncrementalProjectBuilder {
public static final String BUILDER_ID = ResourceBundleManager.BUILDER_ID;
private static final ExtensionManager extensionManager = ExtensionManager.getExtensionManager();
public static I18nAuditor getI18nAuditorByContext(String contextId)
throws NoSuchResourceAuditorException {
for (I18nAuditor auditor : extensionManager.getRegisteredI18nAuditors()) {
if (auditor.getContextId().equals(contextId)) {
return auditor;
}
}
throw new NoSuchResourceAuditorException();
}
public static boolean isResourceAuditable(IResource resource,
Set<String> supportedExtensions) {
for (String ext : supportedExtensions) {
if (resource.getType() == IResource.FILE && !resource.isDerived()
&& resource.getFileExtension() != null
&& (resource.getFileExtension().equalsIgnoreCase(ext))) {
return true;
}
}
return false;
}
@Override
protected IProject[] build(final int kind, Map args,
IProgressMonitor monitor) throws CoreException {
ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
if (kind == FULL_BUILD) {
Logger.logInfo("full project build was triggered");
fullBuild(monitor);
} else {
Logger.logInfo("incremental project build was triggered for: ");
// only perform audit if the resource delta is not empty
IResourceDelta resDelta = getDelta(getProject());
if (resDelta == null) {
Logger.logInfo(" (empty resource delta)");
return;
}
if (resDelta.getAffectedChildren() == null) {
Logger.logInfo(" (empty resource delta)");
return;
}
incrementalBuild(monitor, resDelta);
}
}
}, monitor);
return null;
}
private void incrementalBuild(IProgressMonitor monitor,
IResourceDelta resDelta) throws CoreException {
try {
for (final IResourceDelta changedResource : resDelta
.getAffectedChildren()) {
Logger.logInfo(String.format(" - %s",
changedResource.getResource()));
}
// inspect resource delta
Logger.logInfo(String
.format("looking for resources with the following file endings: %s",
extensionManager.getSupportedFileEndings()));
ResourceFinder csrav = new ResourceFinder(
extensionManager.getSupportedFileEndings());
resDelta.accept(csrav);
Logger.logInfo(String.format(
"Audit triggered for derived resources: %s",
csrav.getResources()));
auditResources(csrav.getResources(), monitor, getProject());
} catch (CoreException e) {
Logger.logError(e);
}
}
public void buildResource(IResource resource, IProgressMonitor monitor) {
if (isResourceAuditable(resource,
extensionManager.getSupportedFileEndings())) {
List<IResource> resources = new ArrayList<IResource>();
resources.add(resource);
// TODO: create instance of progressmonitor and hand it over to
// auditResources
try {
auditResources(resources, monitor, resource.getProject());
} catch (Exception e) {
Logger.logError(e);
}
}
}
public void buildProject(IProgressMonitor monitor, IProject proj) {
try {
ResourceFinder csrav = new ResourceFinder(
extensionManager.getSupportedFileEndings());
proj.accept(csrav);
auditResources(csrav.getResources(), monitor, proj);
} catch (CoreException e) {
Logger.logError(e);
}
}
private void fullBuild(IProgressMonitor monitor) {
buildProject(monitor, getProject());
}
private void auditResources(List<IResource> resources,
IProgressMonitor monitor, IProject project) {
IConfiguration configuration = ConfigurationManager.getInstance()
.getConfiguration();
int work = resources.size();
if (monitor == null) {
monitor = new NullProgressMonitor();
}
monitor.beginTask(
"Audit resource file for Internationalization problems", work);
for (I18nAuditor ra : extensionManager.getRegisteredI18nAuditors()) {
if (ra instanceof I18nResourceAuditor) {
((I18nResourceAuditor) ra).reset();
}
}
for (IResource resource : resources) {
monitor.subTask("'" + resource.getFullPath().toOSString() + "'");
if (monitor.isCanceled()) {
throw new OperationCanceledException();
}
if (!EditorUtils.deleteAuditMarkersForResource(resource)) {
continue;
}
if (ResourceBundleManager.isResourceExcluded(resource)) {
continue;
}
if (!resource.exists()) {
continue;
}
for (I18nAuditor ra : extensionManager.getRegisteredI18nAuditors()) {
if (ra instanceof I18nResourceAuditor
&& !(configuration.getAuditResource())) {
continue;
}
if (ra instanceof I18nRBAuditor
&& !(configuration.getAuditRb())) {
continue;
}
try {
if (monitor.isCanceled()) {
monitor.done();
break;
}
if (ra.isResourceOfType(resource)) {
ra.audit(resource);
}
} catch (Exception e) {
Logger.logError(
"Error during auditing '" + resource.getFullPath()
+ "'", e);
}
}
if (monitor != null) {
monitor.worked(1);
}
}
for (I18nAuditor a : extensionManager.getRegisteredI18nAuditors()) {
if (a instanceof I18nResourceAuditor) {
handleI18NAuditorMarkers((I18nResourceAuditor) a);
}
if (a instanceof I18nRBAuditor) {
handleI18NAuditorMarkers((I18nRBAuditor) a);
((I18nRBAuditor) a).resetProblems();
}
}
monitor.done();
}
private void handleI18NAuditorMarkers(I18nResourceAuditor ra) {
try {
for (ILocation problem : ra.getConstantStringLiterals()) {
EditorUtils
.reportToMarker(
org.eclipse.babel.tapiji.tools.core.util.EditorUtils
.getFormattedMessage(
org.eclipse.babel.tapiji.tools.core.util.EditorUtils.MESSAGE_NON_LOCALIZED_LITERAL,
new String[] { problem
.getLiteral() }),
problem,
MarkerConstants.CAUSE_CONSTANT_LITERAL, "",
(ILocation) problem.getData(), ra
.getContextId());
}
// Report all broken Resource-Bundle references
for (ILocation brokenLiteral : ra.getBrokenResourceReferences()) {
EditorUtils
.reportToMarker(
org.eclipse.babel.tapiji.tools.core.util.EditorUtils
.getFormattedMessage(
org.eclipse.babel.tapiji.tools.core.util.EditorUtils.MESSAGE_BROKEN_RESOURCE_REFERENCE,
new String[] {
brokenLiteral
.getLiteral(),
((ILocation) brokenLiteral
.getData())
.getLiteral() }),
brokenLiteral,
MarkerConstants.CAUSE_BROKEN_REFERENCE,
brokenLiteral.getLiteral(),
(ILocation) brokenLiteral.getData(), ra
.getContextId());
}
// Report all broken definitions to Resource-Bundle
// references
for (ILocation brokenLiteral : ra.getBrokenBundleReferences()) {
EditorUtils
.reportToMarker(
org.eclipse.babel.tapiji.tools.core.util.EditorUtils
.getFormattedMessage(
org.eclipse.babel.tapiji.tools.core.util.EditorUtils.MESSAGE_BROKEN_RESOURCE_BUNDLE_REFERENCE,
new String[] { brokenLiteral
.getLiteral() }),
brokenLiteral,
MarkerConstants.CAUSE_BROKEN_RB_REFERENCE,
brokenLiteral.getLiteral(),
(ILocation) brokenLiteral.getData(), ra
.getContextId());
}
} catch (Exception e) {
Logger.logError(
"Exception during reporting of Internationalization errors",
e);
}
}
private void handleI18NAuditorMarkers(I18nRBAuditor ra) {
IConfiguration configuration = ConfigurationManager.getInstance()
.getConfiguration();
try {
// Report all unspecified keys
if (configuration.getAuditMissingValue()) {
for (ILocation problem : ra.getUnspecifiedKeyReferences()) {
EditorUtils
.reportToRBMarker(
org.eclipse.babel.tapiji.tools.core.util.EditorUtils
.getFormattedMessage(
org.eclipse.babel.tapiji.tools.core.util.EditorUtils.MESSAGE_UNSPECIFIED_KEYS,
new String[] {
problem.getLiteral(),
problem.getFile()
.getName() }),
problem,
MarkerConstants.CAUSE_UNSPEZIFIED_KEY,
problem.getLiteral(), "",
(ILocation) problem.getData(), ra
.getContextId());
}
}
// Report all same values
if (configuration.getAuditSameValue()) {
Map<ILocation, ILocation> sameValues = ra
.getSameValuesReferences();
for (ILocation problem : sameValues.keySet()) {
EditorUtils
.reportToRBMarker(
org.eclipse.babel.tapiji.tools.core.util.EditorUtils
.getFormattedMessage(
org.eclipse.babel.tapiji.tools.core.util.EditorUtils.MESSAGE_SAME_VALUE,
new String[] {
problem.getFile()
.getName(),
sameValues
.get(problem)
.getFile()
.getName(),
problem.getLiteral() }),
problem,
MarkerConstants.CAUSE_SAME_VALUE,
problem.getLiteral(),
sameValues.get(problem).getFile().getName(),
(ILocation) problem.getData(), ra
.getContextId());
}
}
// Report all missing languages
if (configuration.getAuditMissingLanguage()) {
for (ILocation problem : ra.getMissingLanguageReferences()) {
EditorUtils
.reportToRBMarker(
org.eclipse.babel.tapiji.tools.core.util.EditorUtils
.getFormattedMessage(
org.eclipse.babel.tapiji.tools.core.util.EditorUtils.MESSAGE_MISSING_LANGUAGE,
new String[] {
RBFileUtils
.getCorrespondingResourceBundleId(problem
.getFile()),
problem.getLiteral() }),
problem,
MarkerConstants.CAUSE_MISSING_LANGUAGE,
problem.getLiteral(), "",
(ILocation) problem.getData(), ra
.getContextId());
}
}
} catch (Exception e) {
Logger.logError(
"Exception during reporting of Internationalization errors",
e);
}
}
@SuppressWarnings("unused")
private void setProgress(IProgressMonitor monitor, int progress)
throws InterruptedException {
monitor.worked(progress);
if (monitor.isCanceled()) {
throw new OperationCanceledException();
}
if (isInterrupted()) {
throw new InterruptedException();
}
}
@Override
protected void clean(IProgressMonitor monitor) throws CoreException {
// TODO Auto-generated method stub
super.clean(monitor);
}
public static void addBuilderToProject(IProject project) {
Logger.logInfo("Internationalization-Builder registered for '"
+ project.getName() + "'");
// Only for open projects
if (!project.isOpen()) {
return;
}
IProjectDescription description = null;
try {
description = project.getDescription();
} catch (CoreException e) {
Logger.logError(e);
return;
}
// Check if the builder is already associated to the specified project
ICommand[] commands = description.getBuildSpec();
for (ICommand command : commands) {
if (command.getBuilderName().equals(BUILDER_ID)) {
return;
}
}
// Associate the builder with the project
ICommand builderCmd = description.newCommand();
builderCmd.setBuilderName(BUILDER_ID);
List<ICommand> newCommands = new ArrayList<ICommand>();
newCommands.addAll(Arrays.asList(commands));
newCommands.add(builderCmd);
description.setBuildSpec(newCommands.toArray(new ICommand[newCommands
.size()]));
try {
project.setDescription(description, null);
} catch (CoreException e) {
Logger.logError(e);
}
}
public static void removeBuilderFromProject(IProject project) {
// Only for open projects
if (!project.isOpen()) {
return;
}
try {
project.deleteMarkers(EditorUtils.MARKER_ID, false,
IResource.DEPTH_INFINITE);
project.deleteMarkers(EditorUtils.RB_MARKER_ID, false,
IResource.DEPTH_INFINITE);
} catch (CoreException e1) {
Logger.logError(e1);
}
IProjectDescription description = null;
try {
description = project.getDescription();
} catch (CoreException e) {
Logger.logError(e);
return;
}
// remove builder from project
int idx = -1;
ICommand[] commands = description.getBuildSpec();
for (int i = 0; i < commands.length; i++) {
if (commands[i].getBuilderName().equals(BUILDER_ID)) {
idx = i;
break;
}
}
if (idx == -1) {
return;
}
List<ICommand> newCommands = new ArrayList<ICommand>();
newCommands.addAll(Arrays.asList(commands));
newCommands.remove(idx);
description.setBuildSpec(newCommands.toArray(new ICommand[newCommands
.size()]));
try {
project.setDescription(description, null);
} catch (CoreException e) {
Logger.logError(e);
}
}
}