/******************************************************************************* * Copyright (c) 2008 xored software, Inc. * * 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: * xored software, Inc. - initial API and Implementation (Alex Panchenko) *******************************************************************************/ package com.aptana.editor.php.internal.core.builder; import java.lang.reflect.Field; import java.net.URI; import java.text.MessageFormat; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRunnable; 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.jobs.ISchedulingRule; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.FileEditorInput; import org2.eclipse.dltk.compiler.problem.CategorizedProblem; import org2.eclipse.dltk.compiler.problem.DefaultProblem; import org2.eclipse.dltk.compiler.problem.IProblem; import org2.eclipse.dltk.compiler.problem.ProblemCollector; import org2.eclipse.php.internal.core.preferences.CorePreferenceConstants; import com.aptana.core.build.IBuildParticipant.BuildType; import com.aptana.core.build.PreferenceUtil; import com.aptana.core.logging.IdeLog; import com.aptana.core.resources.IUniformResource; import com.aptana.core.resources.MarkerUtils; import com.aptana.core.util.CollectionsUtil; import com.aptana.core.util.EclipseUtil; import com.aptana.core.util.StringUtil; import com.aptana.editor.php.epl.PHPEplPlugin; /** * A problem reporter that can work on a workspace resource or on an external resource, {@link IUniformResource}. */ public class BuildProblemReporter extends ProblemCollector { public static final Pattern filterSplitter = Pattern.compile("####"); public static final String PHPParserValidator_ID = "com.aptana.editor.php.internal.validation.PHPParserValidator"; /* * This can hold an IResource or an IUniformResource, in case the resource is out of workspace. */ private final Object resource; private boolean oldMarkersDeleted = false; private boolean isExternal; private String resourceLocation; private BuildType type; /** * We lazily compile the filters into {@link Pattern}s as we try to match them. */ private Map<String, Pattern> compiledFilters; /** * Constructs a new BuildProblemReporter for a given resource. * * @param resource * Can be {@link IResource} or an {@link IUniformResource} */ public BuildProblemReporter(Object resource, BuildType type) { this.type = type; this.isExternal = (resource instanceof IUniformResource); if (isExternal || resource instanceof IResource) { this.resource = resource; } else { throw new IllegalArgumentException( "The given resource is expected to be an IResource or an IUniformResource"); //$NON-NLS-1$ } resourceLocation = StringUtil.EMPTY; } private static ISchedulingRule getMarkerRule(Object resource) { if (resource instanceof IResource) { return ResourcesPlugin.getWorkspace().getRuleFactory().markerRule((IResource) resource); } return null; } public void flush() { // Performance fix: schedules the error handling as a single workspace update so that we don't trigger a // bunch of resource updated events while problem markers are being added to the file. IWorkspaceRunnable runnable = new IWorkspaceRunnable() { public void run(IProgressMonitor monitor) { updateMarkers(); } }; try { ResourcesPlugin.getWorkspace().run(runnable, getMarkerRule(resource), IWorkspace.AVOID_UPDATE, new NullProgressMonitor()); } catch (CoreException e) { IdeLog.logWarning(PHPEplPlugin.getDefault(), MessageFormat.format(Messages.BuildProblemReporter_UpdateMarkersError, resourceLocation), e, PHPEplPlugin.DEBUG_SCOPE); } } private void updateMarkers() { try { if (EclipseUtil.isTesting()) { return; } IResource workspaceResource = null; IUniformResource externalResource = null; if (isExternal) { externalResource = (IUniformResource) resource; URI uri = externalResource.getURI(); if (uri != null) { resourceLocation = uri.getPath(); } } else { workspaceResource = (IResource) resource; if (workspaceResource == null || !workspaceResource.isAccessible()) { IdeLog.logWarning(PHPEplPlugin.getDefault(), "BuildProblemReporter::flush -> Unexpected null or non-accessible resource"); //$NON-NLS-1$ return; } resourceLocation = workspaceResource.getLocation().toString(); } if (!oldMarkersDeleted) { oldMarkersDeleted = true; if (isExternal) { if(BuildType.BUILD == type) {//BuildType.BUILD的情况下需要删除错误信息 MarkerUtils.deleteMarkers(externalResource, DefaultProblem.MARKER_TYPE_PROBLEM, true); } MarkerUtils.deleteMarkers(externalResource, DefaultProblem.MARKER_TYPE_TASK, true); }else{ if(BuildType.BUILD == type) {//BuildType.BUILD的情况下需要删除错误信息 workspaceResource.deleteMarkers(DefaultProblem.MARKER_TYPE_PROBLEM, true, IResource.DEPTH_INFINITE); } workspaceResource.deleteMarkers(DefaultProblem.MARKER_TYPE_TASK, true, IResource.DEPTH_INFINITE); } } List<String> expressions = getFilters(); for (final IProblem problem : problems) { final String markerType; if (problem instanceof CategorizedProblem) { markerType = ((CategorizedProblem) problem).getMarkerType(); } else { markerType = DefaultProblem.MARKER_TYPE_PROBLEM; } //buildtype类型不匹配或信息被忽略的情况下不需要报告错误信息 if(DefaultProblem.MARKER_TYPE_PROBLEM.equals(markerType) && (!isEnableForBuildType() || isIgnored(problem.getMessage(), expressions))) { continue; } IMarker m = null; if (isExternal) { m = MarkerUtils.createMarker(externalResource, null, markerType); // Make sure we don't persist this marker on an external file. m.setAttribute(IMarker.TRANSIENT, true); } else { m = workspaceResource.createMarker(markerType); } if (m == null || !m.exists()) { IdeLog.logError(PHPEplPlugin.getDefault(), "Error creating a PHP marker", PHPEplPlugin.DEBUG_SCOPE); //$NON-NLS-1$ } if (problem.getSourceLineNumber() >= 0) { m.setAttribute(IMarker.LINE_NUMBER, problem.getSourceLineNumber() + 1); } m.setAttribute(IMarker.MESSAGE, problem.getMessage()); if (problem.getSourceStart() >= 0) { m.setAttribute(IMarker.CHAR_START, problem.getSourceStart()); } if (problem.getSourceEnd() >= 0) { m.setAttribute(IMarker.CHAR_END, problem.getSourceEnd()); } if (DefaultProblem.MARKER_TYPE_PROBLEM.equals(markerType)) { int severity = IMarker.SEVERITY_INFO; if (problem.isError()) { severity = IMarker.SEVERITY_ERROR; } else if (problem.isWarning()) { severity = IMarker.SEVERITY_WARNING; } m.setAttribute(IMarker.SEVERITY, severity); } else { m.setAttribute(IMarker.USER_EDITABLE, Boolean.FALSE); if (problem instanceof TaskInfo) { m.setAttribute(IMarker.PRIORITY, ((TaskInfo) problem).getPriority()); } } } } catch (CoreException e) { IdeLog.logWarning(PHPEplPlugin.getDefault(), MessageFormat.format(Messages.BuildProblemReporter_UpdateMarkersError, resourceLocation), e, PHPEplPlugin.DEBUG_SCOPE); } finally { // in any case, clear the problems problems.clear(); } } /** * Description: 当前的buildtype下是否需要报告错误信息 * @Version1.0 2014-9-17 下午3:06:11 by 黄磊(huanglei@d-heaven.com)创建 * @return */ public boolean isEnableForBuildType() { try{ if(BuildType.RECONCILE == type) { return false; } IEclipsePreferences node = EclipseUtil.instanceScope().getNode("com.aptana.editor.php"); boolean result = node.getBoolean(PreferenceUtil.getEnablementPreferenceKey(PHPParserValidator_ID, type), false); if(!result) { final IEditorPart[] editor = new IEditorPart[1]; Display.getDefault().syncExec(new Runnable() { public void run() { try{ editor[0] = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor(); }catch (Exception e){ } } }); if(editor[0]!=null) { IEditorInput input = editor[0].getEditorInput(); if(input instanceof FileEditorInput) { IFile ifile= ((FileEditorInput)input).getFile(); if(ifile.equals(resource)) { Class editorClass = editor[0].getClass(); Field field = editorClass.getField("openManualValidator"); field.setAccessible(true); return field.getBoolean(editor[0]); } } } } return result; }catch (Exception e){ IdeLog.logError(PHPEplPlugin.getDefault(), e); return false; } } /** * Description: 信息是否需要被忽略 * @Version1.0 2014-9-17 下午3:05:13 by 黄磊(huanglei@d-heaven.com)创建 * @param message * @param expressions * @return */ protected synchronized boolean isIgnored(String message, List<String> expressions) { if (CollectionsUtil.isEmpty(expressions) || message==null) { return false; } if (compiledFilters == null) { compiledFilters = new HashMap<String, Pattern>(expressions.size()); } try{ for (String expression : expressions) { // Lazily compile the filter expressions into Patterns Pattern p = compiledFilters.get(expression); if (p == null) { p = Pattern.compile(expression); compiledFilters.put(expression, p); } if (p.matcher(message).matches()) { return true; } } } catch (Exception e){ IdeLog.logError(PHPEplPlugin.getDefault(), e); } return false; } /** * Description: 获取要忽略错误信息过滤表达式 * @Version1.0 2014-9-17 下午3:04:30 by 黄磊(huanglei@d-heaven.com)创建 * @return */ private List<String> getFilters() { String rawFilters = CorePreferenceConstants.getPreferenceStore().getString(getFiltersPreferenceKey()); if (StringUtil.isEmpty(rawFilters)) { return Collections.emptyList(); } return Arrays.asList(filterSplitter.split(rawFilters)); } private String getFiltersPreferenceKey() { return PreferenceUtil.getFiltersKey(PHPParserValidator_ID); } }