View | Details | Raw Unified | Return to bug 332772 | Differences between
and this patch

Collapse All | Expand All

(-)a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/ApiFilterStore.java (-177 / +38 lines)
Lines 23-40 Link Here
23
import java.util.Map;
23
import java.util.Map;
24
import java.util.Set;
24
import java.util.Set;
25
25
26
import org.w3c.dom.Document;
26
import org.eclipse.core.resources.IFile;
27
import org.w3c.dom.Element;
27
import org.eclipse.core.resources.IFolder;
28
import org.w3c.dom.NodeList;
28
import org.eclipse.core.resources.IProject;
29
29
import org.eclipse.core.resources.IResource;
30
import org.eclipse.pde.api.tools.internal.problems.ApiProblemFactory;
30
import org.eclipse.core.resources.IResourceChangeEvent;
31
import org.eclipse.pde.api.tools.internal.problems.ApiProblemFilter;
31
import org.eclipse.core.resources.IResourceChangeListener;
32
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
32
import org.eclipse.core.resources.IResourceDelta;
33
import org.eclipse.pde.api.tools.internal.provisional.IApiFilterStore;
33
import org.eclipse.core.resources.IncrementalProjectBuilder;
34
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem;
34
import org.eclipse.core.resources.ProjectScope;
35
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblemFilter;
35
import org.eclipse.core.resources.ResourcesPlugin;
36
import org.eclipse.pde.api.tools.internal.util.Util;
36
import org.eclipse.core.resources.WorkspaceJob;
37
38
import org.eclipse.core.runtime.Assert;
37
import org.eclipse.core.runtime.Assert;
39
import org.eclipse.core.runtime.CoreException;
38
import org.eclipse.core.runtime.CoreException;
40
import org.eclipse.core.runtime.IPath;
39
import org.eclipse.core.runtime.IPath;
Lines 47-93 Link Here
47
import org.eclipse.core.runtime.jobs.Job;
46
import org.eclipse.core.runtime.jobs.Job;
48
import org.eclipse.core.runtime.preferences.IScopeContext;
47
import org.eclipse.core.runtime.preferences.IScopeContext;
49
import org.eclipse.core.runtime.preferences.InstanceScope;
48
import org.eclipse.core.runtime.preferences.InstanceScope;
50
51
import org.eclipse.core.resources.IFile;
52
import org.eclipse.core.resources.IFolder;
53
import org.eclipse.core.resources.IProject;
54
import org.eclipse.core.resources.IResource;
55
import org.eclipse.core.resources.IResourceChangeEvent;
56
import org.eclipse.core.resources.IResourceChangeListener;
57
import org.eclipse.core.resources.IResourceDelta;
58
import org.eclipse.core.resources.IncrementalProjectBuilder;
59
import org.eclipse.core.resources.ProjectScope;
60
import org.eclipse.core.resources.ResourcesPlugin;
61
import org.eclipse.core.resources.WorkspaceJob;
62
63
import org.eclipse.jdt.core.IJavaProject;
49
import org.eclipse.jdt.core.IJavaProject;
50
import org.eclipse.pde.api.tools.internal.problems.ApiProblemFilter;
51
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
52
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem;
53
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblemFilter;
54
import org.eclipse.pde.api.tools.internal.util.Util;
55
import org.w3c.dom.Document;
56
import org.w3c.dom.Element;
64
57
65
/**
58
/**
66
 * Base implementation of a filter store for API components
59
 * Base implementation of a filter store for API components
67
 * 
60
 * 
68
 * @since 1.0.0
61
 * @since 1.0.0
69
 */
62
 */
70
public class ApiFilterStore implements IApiFilterStore, IResourceChangeListener {
63
public class ApiFilterStore extends FilterStore implements IResourceChangeListener {
71
	
72
	/**
73
	 * Constant representing the name of the .settings folder
74
	 */
75
	private static final String SETTINGS_FOLDER = ".settings"; //$NON-NLS-1$
76
	public static final String GLOBAL = "!global!"; //$NON-NLS-1$
77
	public static final int CURRENT_STORE_VERSION = 2;
78
79
	/**
80
	 * Represents no filters
81
	 */
82
	private static IApiProblemFilter[] NO_FILTERS = new IApiProblemFilter[0];
83
	
84
	/**
85
	 * The mapping of filters for this store.
86
	 * <pre>
87
	 * HashMap<IResource, HashSet<IApiProblemFilter>>
88
	 * </pre>
89
	 */
90
	private HashMap fFilterMap = null;
91
	
64
	
92
	/**
65
	/**
93
	 * Map used to collect unused {@link IApiProblemFilter}s
66
	 * Map used to collect unused {@link IApiProblemFilter}s
Lines 154-161 Link Here
154
					}
127
					}
155
					String lineDelimiter= getLineDelimiterPreference(file);
128
					String lineDelimiter= getLineDelimiterPreference(file);
156
					String lineSeparator= System.getProperty("line.separator"); //$NON-NLS-1$
129
					String lineSeparator= System.getProperty("line.separator"); //$NON-NLS-1$
157
					if (lineDelimiter != null && !lineDelimiter.equals(lineSeparator))
130
					if (lineDelimiter != null && !lineDelimiter.equals(lineSeparator)) {
158
						xml= xml.replaceAll(lineSeparator, lineDelimiter);
131
						xml= xml.replaceAll(lineSeparator, lineDelimiter);
132
					}
159
					InputStream xstream = Util.getInputStreamFromString(xml);
133
					InputStream xstream = Util.getInputStreamFromString(xml);
160
					if(xstream == null) {
134
					if(xstream == null) {
161
						return Status.CANCEL_STATUS;
135
						return Status.CANCEL_STATUS;
Lines 255-261 Link Here
255
			return;
229
			return;
256
		}
230
		}
257
		initializeApiFilters();
231
		initializeApiFilters();
258
		internalAddFilters(problems, null, true);
232
		internalAddFilters(problems, null);
233
		persistApiFilters();
259
	}
234
	}
260
235
261
	/* (non-Javadoc)
236
	/* (non-Javadoc)
Lines 265-271 Link Here
265
		initializeApiFilters();
240
		initializeApiFilters();
266
		Map pTypeNames = (Map) fFilterMap.get(resource);
241
		Map pTypeNames = (Map) fFilterMap.get(resource);
267
		if(pTypeNames == null) {
242
		if(pTypeNames == null) {
268
			return NO_FILTERS;
243
			return FilterStore.NO_FILTERS;
269
		}
244
		}
270
		List allFilters = new ArrayList();
245
		List allFilters = new ArrayList();
271
		for (Iterator iterator = pTypeNames.values().iterator(); iterator.hasNext(); ) {
246
		for (Iterator iterator = pTypeNames.values().iterator(); iterator.hasNext(); ) {
Lines 525-535 Link Here
525
		return Util.serializeDocument(document);
500
		return Util.serializeDocument(document);
526
	}
501
	}
527
502
528
	/**
503
	/* (non-Javadoc)
529
	 * Initializes the backing filter map for this store from the .api_filters file. Does nothing if the filter store has already been
504
	 * @see org.eclipse.pde.api.tools.internal.FilterStore#initializeApiFilters()
530
	 * initialized.
531
	 */
505
	 */
532
	private synchronized void initializeApiFilters() {
506
	protected synchronized void initializeApiFilters() {
533
		if(fFilterMap != null) {
507
		if(fFilterMap != null) {
534
			return;
508
			return;
535
		}
509
		}
Lines 545-557 Link Here
545
			}
519
			}
546
			return;
520
			return;
547
		}
521
		}
548
		String xml = null;
549
		InputStream contents = null;
522
		InputStream contents = null;
550
		try {
523
		try {
551
			IFile filterFile = (IFile)file;
524
			IFile filterFile = (IFile)file;
552
			if (filterFile.exists()) {
525
			if (filterFile.exists()) {
553
				contents = filterFile.getContents();
526
				contents = filterFile.getContents();
554
				xml = new String(Util.getInputStreamAsCharArray(contents, -1, IApiCoreConstants.UTF_8));
527
				readFilterFile(contents);
555
			}
528
			}
556
		}
529
		}
557
		catch(CoreException e) {
530
		catch(CoreException e) {
Lines 569-669 Link Here
569
				}
542
				}
570
			}
543
			}
571
		}
544
		}
572
		if(xml == null) {
545
		//need to reset the flag during initialization if we are not going to persist
573
			return;
546
		//the filters, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=309635
574
		}
547
		fNeedsSaving = false;
575
		Element root = null;
576
		try {
577
			root = Util.parseDocument(xml);
578
		}
579
		catch(CoreException ce) {
580
			ApiPlugin.log(ce);
581
		}
582
		if (root == null) {
583
			return;
584
		}
585
		if (!root.getNodeName().equals(IApiXmlConstants.ELEMENT_COMPONENT)) {
586
			return;
587
		}
588
		String component = root.getAttribute(IApiXmlConstants.ATTR_ID);
589
		if(component.length() == 0) {
590
			return;
591
		}
592
		String versionValue = root.getAttribute(IApiXmlConstants.ATTR_VERSION);
593
		int currentVersion = Integer.parseInt(IApiXmlConstants.API_FILTER_STORE_CURRENT_VERSION);
594
		int version = 0;
595
		if(versionValue.length() != 0) {
596
			try {
597
				version = Integer.parseInt(versionValue);
598
			} catch (NumberFormatException e) {
599
				// ignore
600
			}
601
		}
602
		if (version != currentVersion) {
603
			// we discard all filters since there is no way to retrieve the type name
604
			fNeedsSaving = true;
605
			persistApiFilters();
606
			return;
607
		}
608
		NodeList resources = root.getElementsByTagName(IApiXmlConstants.ELEMENT_RESOURCE);
609
		ArrayList newfilters = new ArrayList();
610
		ArrayList comments = new ArrayList();
611
		for(int i = 0; i < resources.getLength(); i++) {
612
			Element element = (Element) resources.item(i);
613
			String path = element.getAttribute(IApiXmlConstants.ATTR_PATH);
614
			if(path.length() == 0) {
615
				continue;
616
			}
617
			String typeName = element.getAttribute(IApiXmlConstants.ATTR_TYPE);
618
			if (typeName.length() == 0) {
619
				typeName = null;
620
			}
621
			IProject project = (IProject) ResourcesPlugin.getWorkspace().getRoot().findMember(component);
622
			if(project == null) {
623
				continue;
624
			}
625
			IResource resource = project.findMember(new Path(path));
626
			if(resource == null) {
627
				continue;
628
			}
629
			NodeList filters = element.getElementsByTagName(IApiXmlConstants.ELEMENT_FILTER);
630
			for(int j = 0; j < filters.getLength(); j++) {
631
				element = (Element) filters.item(j);
632
				int id = loadIntegerAttribute(element, IApiXmlConstants.ATTR_ID);
633
				if(id <= 0) {
634
					continue;
635
				}
636
				String[] messageargs = null;
637
				NodeList elements = element.getElementsByTagName(IApiXmlConstants.ELEMENT_PROBLEM_MESSAGE_ARGUMENTS);
638
				if (elements.getLength() != 1) continue;
639
				Element messageArguments = (Element) elements.item(0);
640
				NodeList arguments = messageArguments.getElementsByTagName(IApiXmlConstants.ELEMENT_PROBLEM_MESSAGE_ARGUMENT);
641
				int length = arguments.getLength();
642
				messageargs = new String[length];
643
				for (int k = 0; k < length; k++) {
644
					Element messageArgument = (Element) arguments.item(k);
645
					messageargs[k] = messageArgument.getAttribute(IApiXmlConstants.ATTR_VALUE);
646
				}
647
				String comment = element.getAttribute(IApiXmlConstants.ATTR_COMMENT);
648
				comments.add((comment.length() < 1 ? null : comment));
649
				newfilters.add(ApiProblemFactory.newApiProblem(resource.getProjectRelativePath().toPortableString(),
650
						typeName,
651
						messageargs, null, null, -1, -1, -1, id));
652
			}
653
		}
654
		internalAddFilters((IApiProblem[]) newfilters.toArray(new IApiProblem[newfilters.size()]), 
655
				(String[]) comments.toArray(new String[comments.size()]), 
656
				false);
657
		newfilters.clear();
658
	}
548
	}
659
	
549
	
660
	/**
550
	/* (non-Javadoc)
661
	 * Internal use method that allows auto-persisting of the filter file to be turned on or off
551
	 * @see org.eclipse.pde.api.tools.internal.FilterStore#internalAddFilters(org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem[], java.lang.String[])
662
	 * @param problems the problems to add the the store
663
	 * @param comments the comments associated with each problem
664
	 * @param persist if the filters should be auto-persisted after they are added
665
	 */
552
	 */
666
	private synchronized void internalAddFilters(IApiProblem[] problems, String[] comments, boolean persist) {
553
	protected synchronized void internalAddFilters(IApiProblem[] problems, String[] comments) {
667
		Set filters = null;
554
		Set filters = null;
668
		for(int i = 0; i < problems.length; i++) {
555
		for(int i = 0; i < problems.length; i++) {
669
			IApiProblem problem = problems[i];
556
			IApiProblem problem = problems[i];
Lines 695-708 Link Here
695
			}
582
			}
696
			fNeedsSaving |= filters.add(filter);
583
			fNeedsSaving |= filters.add(filter);
697
		}
584
		}
698
		if(persist) {
699
			persistApiFilters();
700
		}
701
		else {
702
			//need to reset the flag during initialization if we are not going to persist
703
			//the filters, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=309635
704
			fNeedsSaving = false;
705
		}
706
	}
585
	}
707
	
586
	
708
	/**
587
	/**
Lines 715-746 Link Here
715
	}
594
	}
716
	
595
	
717
	/**
596
	/**
718
	 * Loads the specified integer attribute from the given xml element
719
	 * @param element
720
	 * @param name
721
	 * @return
722
	 */
723
	private static int loadIntegerAttribute(Element element, String name) {
724
		String value = element.getAttribute(name);
725
		if(value.length() == 0) {
726
			return -1;
727
		}
728
		try {
729
			int number = Integer.parseInt(value);
730
			return number;
731
		}
732
		catch(NumberFormatException nfe) {}
733
		return -1;
734
	}
735
	/**
736
	 * @return the {@link IPath} to the filters file
597
	 * @return the {@link IPath} to the filters file
737
	 */
598
	 */
738
	IPath getFilterFilePath(boolean includeproject) {
599
	IPath getFilterFilePath(boolean includeproject) {
739
		if(includeproject) {
600
		if(includeproject) {
740
			IPath path = fProject.getPath();
601
			IPath path = fProject.getPath();
741
			return path.append(SETTINGS_FOLDER).append(IApiCoreConstants.API_FILTERS_XML_NAME);
602
			return path.append(FilterStore.SETTINGS_FOLDER).append(IApiCoreConstants.API_FILTERS_XML_NAME);
742
		}
603
		}
743
		return new Path(SETTINGS_FOLDER).append(IApiCoreConstants.API_FILTERS_XML_NAME);
604
		return new Path(FilterStore.SETTINGS_FOLDER).append(IApiCoreConstants.API_FILTERS_XML_NAME);
744
	}
605
	}
745
606
746
	static String getLineDelimiterPreference(IFile file) {
607
	static String getLineDelimiterPreference(IFile file) {
Lines 841-851 Link Here
841
			}
702
			}
842
			int size = unused.size();
703
			int size = unused.size();
843
			if (size == 0) {
704
			if (size == 0) {
844
				return NO_FILTERS;
705
				return FilterStore.NO_FILTERS;
845
			}
706
			}
846
			return (IApiProblemFilter[]) unused.toArray(new IApiProblemFilter[size]);
707
			return (IApiProblemFilter[]) unused.toArray(new IApiProblemFilter[size]);
847
		}
708
		}
848
		return NO_FILTERS;
709
		return FilterStore.NO_FILTERS;
849
	}
710
	}
850
	
711
	
851
	/**
712
	/**
(-)a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/CoreMessages.java (+1 lines)
Lines 23-28 Link Here
23
	public static String ApiBaseline_4;
23
	public static String ApiBaseline_4;
24
	public static String ApiBaseline_5;
24
	public static String ApiBaseline_5;
25
	public static String ApiBaseline_6;
25
	public static String ApiBaseline_6;
26
	public static String FilterStore_0;
26
	public static String ProjectComponent_could_not_locate_model;
27
	public static String ProjectComponent_could_not_locate_model;
27
	static {
28
	static {
28
		// initialize resource bundle
29
		// initialize resource bundle
(-)a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/FilterStore.java (+416 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.pde.api.tools.internal;
12
13
import java.io.File;
14
import java.io.FileInputStream;
15
import java.io.IOException;
16
import java.io.InputStream;
17
import java.util.ArrayList;
18
import java.util.HashMap;
19
import java.util.HashSet;
20
import java.util.Iterator;
21
import java.util.Set;
22
import java.util.zip.ZipEntry;
23
import java.util.zip.ZipFile;
24
25
import org.eclipse.core.resources.IResource;
26
import org.eclipse.core.runtime.CoreException;
27
import org.eclipse.core.runtime.Path;
28
import org.eclipse.pde.api.tools.internal.model.BundleComponent;
29
import org.eclipse.pde.api.tools.internal.problems.ApiProblemFactory;
30
import org.eclipse.pde.api.tools.internal.problems.ApiProblemFilter;
31
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
32
import org.eclipse.pde.api.tools.internal.provisional.IApiFilterStore;
33
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem;
34
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblemFilter;
35
import org.eclipse.pde.api.tools.internal.util.Util;
36
import org.w3c.dom.Element;
37
import org.w3c.dom.NodeList;
38
39
/**
40
 * A generic {@link IApiFilterStore} that does not depend on workspace resources
41
 * to filter {@link IApiProblem}s.
42
 * <br>
43
 * This filter store can have filters added and removed from it, but those changes 
44
 * are not saved.
45
 */
46
public class FilterStore implements IApiFilterStore {
47
48
	public static final String GLOBAL = "!global!"; //$NON-NLS-1$
49
	/**
50
	 * Represents no filters
51
	 */
52
	public static IApiProblemFilter[] NO_FILTERS = new IApiProblemFilter[0];
53
	/**
54
	 * The current version of this filter store file format
55
	 */
56
	public static final int CURRENT_STORE_VERSION = 2;
57
	/**
58
	 * Constant representing the name of the .settings folder
59
	 */
60
	static final String SETTINGS_FOLDER = ".settings"; //$NON-NLS-1$
61
	/**
62
	 * The mapping of filters for this store.
63
	 */
64
	protected HashMap fFilterMap = null;
65
	/**
66
	 * The bundle component backing this store
67
	 */
68
	private BundleComponent fComponent = null;
69
70
	/**
71
	 * Constructor
72
	 */
73
	public FilterStore() {}
74
	
75
	/**
76
	 * Constructor
77
	 * @param component
78
	 */
79
	public FilterStore(BundleComponent component) {
80
		fComponent = component;
81
	}
82
	
83
	/* (non-Javadoc)
84
	 * @see org.eclipse.pde.api.tools.internal.provisional.IApiFilterStore#addFilters(org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblemFilter[])
85
	 */
86
	public void addFilters(IApiProblemFilter[] filters) {
87
		if(filters != null && filters.length > 0) {
88
			initializeApiFilters();
89
			for (int i = 0; i < filters.length; i++) {
90
				fFilterMap.put(filters[i].getComponentId(), filters[i]);
91
			}
92
		}
93
	}
94
95
	/* (non-Javadoc)
96
	 * @see org.eclipse.pde.api.tools.internal.provisional.IApiFilterStore#addFiltersFor(org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem[])
97
	 */
98
	public void addFiltersFor(IApiProblem[] problems) {
99
		if(problems != null && problems.length > 0) {
100
			initializeApiFilters();
101
			internalAddFilters(problems, null);
102
		}
103
	}
104
105
	/* (non-Javadoc)
106
	 * @see org.eclipse.pde.api.tools.internal.provisional.IApiFilterStore#getFilters(org.eclipse.core.resources.IResource)
107
	 */
108
	public IApiProblemFilter[] getFilters(IResource resource) {
109
		return null;
110
	}
111
112
	/* (non-Javadoc)
113
	 * @see org.eclipse.pde.api.tools.internal.provisional.IApiFilterStore#getResources()
114
	 */
115
	public IResource[] getResources() {
116
		return null;
117
	}
118
119
	/* (non-Javadoc)
120
	 * @see org.eclipse.pde.api.tools.internal.provisional.IApiFilterStore#removeFilters(org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblemFilter[])
121
	 */
122
	public boolean removeFilters(IApiProblemFilter[] filters) {
123
		if(filters != null && filters.length > 0) {
124
			initializeApiFilters();
125
			boolean removed = true;
126
			for(int i = 0; i < filters.length; i++) {
127
				removed &= (fFilterMap.remove(filters[i].getComponentId()) != null);
128
			}
129
			return removed;
130
		}
131
		return false;
132
	}
133
134
	/**
135
	 * Loads the filters from the .api_filters file
136
	 */
137
	protected synchronized void initializeApiFilters() {
138
		if(fFilterMap == null) {
139
			ZipFile jarFile = null;
140
			InputStream filterstream = null;
141
			File loc = new File(fComponent.getLocation());
142
			String extension = new Path(loc.getName()).getFileExtension();
143
			try {
144
				if (extension != null && extension.equals("jar") && loc.isFile()) { //$NON-NLS-1$
145
					jarFile = new ZipFile(loc, ZipFile.OPEN_READ);
146
					ZipEntry filterfile = jarFile.getEntry(IApiCoreConstants.API_FILTERS_XML_NAME);
147
					if (filterfile != null) {
148
						filterstream = jarFile.getInputStream(filterfile);
149
					}
150
				} else {
151
					File file = new File(loc, SETTINGS_FOLDER+File.separator+IApiCoreConstants.API_FILTERS_XML_NAME);
152
					if (file.exists()) {
153
						filterstream = new FileInputStream(file);
154
					}
155
				}
156
				if (filterstream == null) {
157
					return;
158
				}
159
			} catch (IOException e) {
160
				ApiPlugin.log(e);
161
			} finally {
162
				fComponent.closingZipFileAndStream(filterstream, jarFile);
163
			}
164
		}
165
	}
166
	
167
	/* (non-Javadoc)
168
	 * @see org.eclipse.pde.api.tools.internal.provisional.IApiFilterStore#isFiltered(org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem)
169
	 */
170
	public boolean isFiltered(IApiProblem problem) {
171
		if (fFilterMap == null || fFilterMap.isEmpty()) {
172
			return false;
173
		}
174
		String typeName = problem.getTypeName();
175
		if (typeName == null || typeName.length() == 0) {
176
			typeName = GLOBAL;
177
		}
178
		Set filters = (Set) fFilterMap.get(typeName);
179
		if (filters == null) {
180
			return false;
181
		}
182
		for (Iterator iterator = filters.iterator(); iterator.hasNext();) {
183
			IApiProblemFilter filter = (IApiProblemFilter) iterator.next();
184
			if (problemsMatch(filter.getUnderlyingProblem(), problem)) {
185
				return true;
186
			}
187
		}
188
		return false;
189
	}
190
	
191
	/**
192
	 * Returns <code>true</code> if the attributes of the problems match, <code>false</code> otherwise
193
	 * 
194
	 * @param filterProblem the problem from the filter store
195
	 * @param problem the problem from the builder
196
	 * @return <code>true</code> if the problems match, <code>false</code> otherwise
197
	 */
198
	protected boolean problemsMatch(IApiProblem filterProblem, IApiProblem problem) {
199
		if (problem.getId() == filterProblem.getId()) {
200
			// check arguments
201
			String problemPath = problem.getResourcePath();
202
			String filterProblemPath = filterProblem.getResourcePath();
203
			if (problemPath == null) {
204
				if (filterProblemPath != null) {
205
					return false;
206
				}
207
			} else if (filterProblemPath == null) {
208
				return false;
209
			} else if (!new Path(problemPath).equals(new Path(filterProblemPath))) {
210
				return false;
211
			}
212
			String problemTypeName = problem.getTypeName();
213
			String filterProblemTypeName = filterProblem.getTypeName();
214
			if (problemTypeName == null) {
215
				if (filterProblemTypeName != null) {
216
					return false;
217
				}
218
			} else if (filterProblemTypeName == null) {
219
				return false;
220
			} else if (!problemTypeName.equals(filterProblemTypeName)) {
221
				return false;
222
			}
223
			return argumentsEquals(problem.getMessageArguments(), filterProblem.getMessageArguments());
224
		}
225
		return false;
226
	}
227
	
228
	/**
229
	 * Returns if the arrays of message arguments are equal. 
230
	 * <br>
231
	 * The arrays are considered equal iff:
232
	 * <ul>
233
	 * <li>both are <code>null</code></li>
234
	 * <li>both are the same length</li>
235
	 * <li>both have equal elements at equal positions in the array</li>
236
	 * </ul>
237
	 * @param problemMessageArguments
238
	 * @param filterProblemMessageArguments
239
	 * @return <code>true</code> if the arrays are equal, <code>false</code> otherwise
240
	 */
241
	private boolean argumentsEquals(String[] problemMessageArguments, String[] filterProblemMessageArguments) {
242
		// filter problems message arguments are always simple name
243
		// problem message arguments are fully qualified name outside the IDE
244
		int length = problemMessageArguments.length;
245
		if (length == filterProblemMessageArguments.length) {
246
			for (int i = 0; i < length; i++) {
247
				String problemMessageArgument = problemMessageArguments[i];
248
				String filterProblemMessageArgument = filterProblemMessageArguments[i];
249
				if (problemMessageArgument.equals(filterProblemMessageArgument)) {
250
					continue;
251
				}
252
				int index = problemMessageArgument.lastIndexOf('.');
253
				int filterProblemIndex = filterProblemMessageArgument.lastIndexOf('.');
254
				if (index == -1) {
255
					if (filterProblemIndex == -1) {
256
						return false; // simple names should match
257
					}
258
					if (filterProblemMessageArgument.substring(filterProblemIndex + 1).equals(problemMessageArgument)) {
259
						continue;
260
					} else {
261
						return false;
262
					}
263
				} else if (filterProblemIndex != -1) {
264
					return false; // fully qualified name should match
265
				} else {
266
					if (problemMessageArgument.substring(index + 1).equals(filterProblemMessageArgument)) {
267
						continue;
268
					} else {
269
						return false;
270
					}
271
				}
272
			}
273
			return true;
274
		}
275
		return false;
276
	}
277
	
278
	/* (non-Javadoc)
279
	 * @see org.eclipse.pde.api.tools.internal.provisional.IApiFilterStore#dispose()
280
	 */
281
	public void dispose() {
282
		if(fFilterMap != null) {
283
			fFilterMap.clear();
284
			fFilterMap = null;
285
		}
286
	}
287
	
288
	/**
289
	 * Reads the API problem filter file and calls back to {@link #addFilters(IApiProblemFilter[])} 
290
	 * to store the filters.
291
	 * <br>
292
	 * This method will not close the given input stream when done reading it.
293
	 * 
294
	 * @param contents the {@link InputStream} for the contents of the filter file, <code>null</code> is not allowed.
295
	 * @throws IOException if the stream cannot be read or fails
296
	 */
297
	protected void readFilterFile(InputStream contents) throws IOException {
298
		if(contents == null) {
299
			throw new IOException(CoreMessages.FilterStore_0);
300
		}
301
		String xml = new String(Util.getInputStreamAsCharArray(contents, -1, IApiCoreConstants.UTF_8));
302
		Element root = null;
303
		try {
304
			root = Util.parseDocument(xml);
305
		}
306
		catch(CoreException ce) {
307
			ApiPlugin.log(ce);
308
		}
309
		if (root == null) {
310
			return;
311
		}
312
		if (!root.getNodeName().equals(IApiXmlConstants.ELEMENT_COMPONENT)) {
313
			return;
314
		}
315
		String component = root.getAttribute(IApiXmlConstants.ATTR_ID);
316
		if(component.length() == 0) {
317
			return;
318
		}
319
		String versionValue = root.getAttribute(IApiXmlConstants.ATTR_VERSION);
320
		int currentVersion = Integer.parseInt(IApiXmlConstants.API_FILTER_STORE_CURRENT_VERSION);
321
		int version = 0;
322
		if(versionValue.length() != 0) {
323
			try {
324
				version = Integer.parseInt(versionValue);
325
			} catch (NumberFormatException e) {
326
				// ignore
327
			}
328
		}
329
		if (version != currentVersion) {
330
			return;
331
		}
332
		NodeList resources = root.getElementsByTagName(IApiXmlConstants.ELEMENT_RESOURCE);
333
		ArrayList newfilters = new ArrayList();
334
		ArrayList comments = new ArrayList();
335
		for(int i = 0; i < resources.getLength(); i++) {
336
			Element element = (Element) resources.item(i);
337
			String typeName = element.getAttribute(IApiXmlConstants.ATTR_TYPE);
338
			if (typeName.length() == 0) {
339
				// if there is no type attribute, an empty string is returned
340
				typeName = null;
341
			}
342
			String path = element.getAttribute(IApiXmlConstants.ATTR_PATH);
343
			NodeList filters = element.getElementsByTagName(IApiXmlConstants.ELEMENT_FILTER);
344
			for(int j = 0; j < filters.getLength(); j++) {
345
				element = (Element) filters.item(j);
346
				int id = loadIntegerAttribute(element, IApiXmlConstants.ATTR_ID);
347
				if(id <= 0) {
348
					continue;
349
				}
350
				String[] messageargs = null;
351
				NodeList elements = element.getElementsByTagName(IApiXmlConstants.ELEMENT_PROBLEM_MESSAGE_ARGUMENTS);
352
				if (elements.getLength() != 1) continue;
353
				Element messageArguments = (Element) elements.item(0);
354
				NodeList arguments = messageArguments.getElementsByTagName(IApiXmlConstants.ELEMENT_PROBLEM_MESSAGE_ARGUMENT);
355
				int length = arguments.getLength();
356
				messageargs = new String[length];
357
				String comment = element.getAttribute(IApiXmlConstants.ATTR_COMMENT);
358
				comments.add((comment.length() < 1 ? null : comment));
359
				for (int k = 0; k < length; k++) {
360
					Element messageArgument = (Element) arguments.item(k);
361
					messageargs[k] = messageArgument.getAttribute(IApiXmlConstants.ATTR_VALUE);
362
				}
363
				newfilters.add(ApiProblemFactory.newApiProblem(path, typeName, messageargs, null, null, -1, -1, -1, id));
364
			}
365
		}
366
		internalAddFilters(
367
				(IApiProblem[]) newfilters.toArray(new IApiProblem[newfilters.size()]),
368
				(String[]) comments.toArray(new String[comments.size()]));
369
		newfilters.clear();
370
	}
371
	
372
	/**
373
	 * Internal use method that allows auto-persisting of the filter file to be turned on or off
374
	 * @param problems the problems to add the the store
375
	 * @param persist if the filters should be auto-persisted after they are added
376
	 */
377
	protected void internalAddFilters(IApiProblem[] problems, String[] comments) {
378
		if(problems == null) {
379
			return;
380
		}
381
		for(int i = 0; i < problems.length; i++) {
382
			IApiProblem problem = problems[i];
383
			IApiProblemFilter filter = new ApiProblemFilter(fComponent.getSymbolicName(), problem, comments[i]);
384
			String typeName = problem.getTypeName();
385
			if (typeName == null) {
386
				typeName = GLOBAL;
387
			}
388
			Set filters = (Set) fFilterMap.get(typeName);
389
			if(filters == null) {
390
				filters = new HashSet();
391
				fFilterMap.put(typeName, filters);
392
			}
393
			filters.add(filter);
394
		}
395
	}
396
	
397
	/**
398
	 * Loads the specified integer attribute from the given XML element
399
	 * @param element the XML element
400
	 * @param name the name of the attribute
401
	 * @return the specified value in XML or -1
402
	 */
403
	protected int loadIntegerAttribute(Element element, String name) {
404
		String value = element.getAttribute(name);
405
		if(value.length() == 0) {
406
			return -1;
407
		}
408
		try {
409
			int number = Integer.parseInt(value);
410
			return number;
411
		}
412
		catch(NumberFormatException nfe) {}
413
		return -1;
414
	}
415
416
}
(-)a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/IApiXmlConstants.java (-1 / +1 lines)
Lines 25-31 Link Here
25
	/**
25
	/**
26
	 * Constant representing the current version for API filter store files
26
	 * Constant representing the current version for API filter store files
27
	 */
27
	 */
28
	public static final String API_FILTER_STORE_CURRENT_VERSION = Integer.toString(ApiFilterStore.CURRENT_STORE_VERSION);
28
	public static final String API_FILTER_STORE_CURRENT_VERSION = Integer.toString(FilterStore.CURRENT_STORE_VERSION);
29
	/**
29
	/**
30
	 * Constant representing the current version for API profile files
30
	 * Constant representing the current version for API profile files
31
	 */
31
	 */
(-)a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/coremessages.properties (+1 lines)
Lines 15-18 Link Here
15
ApiBaseline_4=Baseline has bundles requiring unavailable execution environments
15
ApiBaseline_4=Baseline has bundles requiring unavailable execution environments
16
ApiBaseline_5={0} is unavailable
16
ApiBaseline_5={0} is unavailable
17
ApiBaseline_6=Baseline not bound - there are no installed VMs compatible with the required execution environments
17
ApiBaseline_6=Baseline not bound - there are no installed VMs compatible with the required execution environments
18
FilterStore_0=Cannot read API problem filters from a null stream
18
ProjectComponent_could_not_locate_model=Could not locate the plugin model base for project: {0}
19
ProjectComponent_could_not_locate_model=Could not locate the plugin model base for project: {0}
(-)a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/model/BundleComponent.java (-37 / +3 lines)
Lines 29-35 Link Here
29
import java.util.Map;
29
import java.util.Map;
30
import java.util.Set;
30
import java.util.Set;
31
import java.util.jar.JarFile;
31
import java.util.jar.JarFile;
32
import java.util.jar.Manifest;
33
import java.util.zip.ZipEntry;
32
import java.util.zip.ZipEntry;
34
import java.util.zip.ZipFile;
33
import java.util.zip.ZipFile;
35
34
Lines 56-61 Link Here
56
import org.eclipse.pde.api.tools.internal.ApiDescriptionProcessor;
55
import org.eclipse.pde.api.tools.internal.ApiDescriptionProcessor;
57
import org.eclipse.pde.api.tools.internal.BundleVersionRange;
56
import org.eclipse.pde.api.tools.internal.BundleVersionRange;
58
import org.eclipse.pde.api.tools.internal.CompositeApiDescription;
57
import org.eclipse.pde.api.tools.internal.CompositeApiDescription;
58
import org.eclipse.pde.api.tools.internal.FilterStore;
59
import org.eclipse.pde.api.tools.internal.IApiCoreConstants;
59
import org.eclipse.pde.api.tools.internal.IApiCoreConstants;
60
import org.eclipse.pde.api.tools.internal.RequiredComponentDescription;
60
import org.eclipse.pde.api.tools.internal.RequiredComponentDescription;
61
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
61
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
Lines 529-536 Link Here
529
	 * @see org.eclipse.pde.api.tools.internal.AbstractApiComponent#createApiFilterStore()
529
	 * @see org.eclipse.pde.api.tools.internal.AbstractApiComponent#createApiFilterStore()
530
	 */
530
	 */
531
	protected IApiFilterStore createApiFilterStore() throws CoreException {
531
	protected IApiFilterStore createApiFilterStore() throws CoreException {
532
		//always return a new empty store since we do not support filtering from bundles
532
		return new FilterStore(this);
533
		return null;
534
	}
533
	}
535
	
534
	
536
	/**
535
	/**
Lines 814-854 Link Here
814
		}
813
		}
815
		return null;
814
		return null;
816
	}
815
	}
817
	
818
	/**
819
	 * Reads and returns this bunlde's manifest in a Manifest object.
820
	 * The bundle may be in a jar or in a directory at the specified location.
821
	 * 
822
	 * @param bundleLocation root location of the bundle
823
	 * @return manifest or <code>null</code> if not present
824
	 * @throws IOException if unable to parse
825
	 */
826
	protected Manifest readManifest(File bundleLocation) throws IOException {
827
		ZipFile jarFile = null;
828
		InputStream manifestStream = null;
829
		try {
830
			String extension = new Path(bundleLocation.getName()).getFileExtension();
831
			if (extension != null && extension.equals("jar") && bundleLocation.isFile()) { //$NON-NLS-1$
832
				jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ);
833
				ZipEntry manifestEntry = jarFile.getEntry(JarFile.MANIFEST_NAME);
834
				if (manifestEntry != null) {
835
					manifestStream = jarFile.getInputStream(manifestEntry);
836
				}
837
			} else {
838
				File file = new File(bundleLocation, JarFile.MANIFEST_NAME);
839
				if (file.exists())
840
					manifestStream = new FileInputStream(file);
841
			}
842
			if (manifestStream == null) {
843
				return null;
844
			}
845
			return new Manifest(manifestStream);
846
		} finally {
847
			closingZipFileAndStream(manifestStream, jarFile);
848
		}
849
	}
850
816
851
	void closingZipFileAndStream(InputStream stream, ZipFile jarFile) {
817
	public void closingZipFileAndStream(InputStream stream, ZipFile jarFile) {
852
		try {
818
		try {
853
			if (stream != null) {
819
			if (stream != null) {
854
				stream.close();
820
				stream.close();
(-)a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/search/UseSearchRequestor.java (-1 / +38 lines)
Lines 19-24 Link Here
19
import org.eclipse.pde.api.tools.internal.builder.ReferenceAnalyzer;
19
import org.eclipse.pde.api.tools.internal.builder.ReferenceAnalyzer;
20
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
20
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
21
import org.eclipse.pde.api.tools.internal.provisional.IApiAnnotations;
21
import org.eclipse.pde.api.tools.internal.provisional.IApiAnnotations;
22
import org.eclipse.pde.api.tools.internal.provisional.IApiFilterStore;
22
import org.eclipse.pde.api.tools.internal.provisional.VisibilityModifiers;
23
import org.eclipse.pde.api.tools.internal.provisional.VisibilityModifiers;
23
import org.eclipse.pde.api.tools.internal.provisional.builder.IApiProblemDetector;
24
import org.eclipse.pde.api.tools.internal.provisional.builder.IApiProblemDetector;
24
import org.eclipse.pde.api.tools.internal.provisional.builder.IReference;
25
import org.eclipse.pde.api.tools.internal.provisional.builder.IReference;
Lines 29-34 Link Here
29
import org.eclipse.pde.api.tools.internal.provisional.model.IApiScope;
30
import org.eclipse.pde.api.tools.internal.provisional.model.IApiScope;
30
import org.eclipse.pde.api.tools.internal.provisional.model.IApiType;
31
import org.eclipse.pde.api.tools.internal.provisional.model.IApiType;
31
import org.eclipse.pde.api.tools.internal.provisional.model.IApiTypeContainer;
32
import org.eclipse.pde.api.tools.internal.provisional.model.IApiTypeContainer;
33
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem;
32
import org.eclipse.pde.api.tools.internal.provisional.search.IApiSearchRequestor;
34
import org.eclipse.pde.api.tools.internal.provisional.search.IApiSearchRequestor;
33
35
34
/**
36
/**
Lines 46-51 Link Here
46
	 */
48
	 */
47
	private Set fComponentIds = null;
49
	private Set fComponentIds = null;
48
50
51
	/**
52
	 * The current {@link IApiFilterStore} from the current {@link IApiComponent} context we are visiting
53
	 */
54
	private IApiFilterStore currentStore = null;
55
	
56
	/**
57
	 * An {@link IApiFilterStore} that was set from an external source
58
	 * 
59
	 * @see #setGlobalFilterStore
60
	 */
61
	private IApiFilterStore globalStore = null;
62
	
49
	/**
63
	/**
50
	 * The mask to use while searching
64
	 * The mask to use while searching
51
	 */
65
	 */
Lines 94-105 Link Here
94
				if(includesIllegalUse()) {
108
				if(includesIllegalUse()) {
95
					fAnalyzer.buildProblemDetectors(component, ProblemDetectorBuilder.K_USE, null);
109
					fAnalyzer.buildProblemDetectors(component, ProblemDetectorBuilder.K_USE, null);
96
				}
110
				}
111
				currentStore = component.getFilterStore();
97
				return true;
112
				return true;
98
			}
113
			}
99
		}
114
		}
100
		catch(CoreException ce) {
115
		catch(CoreException ce) {
101
			//do nothing, return false
116
			//do nothing, return false
102
		}
117
		}
118
		currentStore = null;
103
		return false;
119
		return false;
104
	}
120
	}
105
	
121
	
Lines 195-201 Link Here
195
				Reference ref = (Reference) reference;
211
				Reference ref = (Reference) reference;
196
				ref.setFlags(IReference.F_ILLEGAL);
212
				ref.setFlags(IReference.F_ILLEGAL);
197
				try {
213
				try {
198
					ref.addProblems(((AbstractProblemDetector)detectors[i]).createProblem(reference));
214
					IApiProblem pb = ((AbstractProblemDetector)detectors[i]).createProblem(reference);
215
					if(!isFiltered(pb)) {
216
						ref.addProblems(pb);
217
					}
199
				} catch (CoreException e) {
218
				} catch (CoreException e) {
200
					ApiPlugin.log(e);
219
					ApiPlugin.log(e);
201
				}
220
				}
Lines 203-208 Link Here
203
			}
222
			}
204
		}
223
		}
205
		return false;
224
		return false;
225
	}
226
	
227
	/**
228
	 * Returns if the given problem is filtered
229
	 * @param problem
230
	 * @return <code>true</code> is filtered, false otherwise
231
	 */
232
	boolean isFiltered(IApiProblem problem) throws CoreException {
233
		return (currentStore != null && currentStore.isFiltered(problem)) || 
234
				(globalStore != null && globalStore.isFiltered(problem));
206
	}
235
	}
207
	
236
	
208
	/* (non-Javadoc)
237
	/* (non-Javadoc)
Lines 260-263 Link Here
260
	public void setJarPatterns(String[] patterns) {
289
	public void setJarPatterns(String[] patterns) {
261
		jarPatterns = patterns;
290
		jarPatterns = patterns;
262
	}
291
	}
292
	
293
	/**
294
	 * Allows a global {@link IApiFilterStore} to be used to filter all references found during the scan
295
	 * @param store the store to set or <code>null</code> to remove the store
296
	 */
297
	public void setGlobalFilterStore(IApiFilterStore store) {
298
		globalStore = store;
299
	}
263
}
300
}
(-)a/apitools/org.eclipse.pde.api.tools/src_ant/org/eclipse/pde/api/tools/internal/tasks/APIToolsAnalysisTask.java (-295 / +2 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2008, 2011 IBM Corporation and others.
2
 * Copyright (c) 2008, 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 14-20 Link Here
14
import java.io.File;
14
import java.io.File;
15
import java.io.FileInputStream;
15
import java.io.FileInputStream;
16
import java.io.IOException;
16
import java.io.IOException;
17
import java.io.InputStream;
18
import java.io.PrintWriter;
17
import java.io.PrintWriter;
19
import java.io.StringWriter;
18
import java.io.StringWriter;
20
import java.util.ArrayList;
19
import java.util.ArrayList;
Lines 29-46 Link Here
29
import java.util.Set;
28
import java.util.Set;
30
29
31
import org.apache.tools.ant.BuildException;
30
import org.apache.tools.ant.BuildException;
32
import org.eclipse.core.resources.IResource;
33
import org.eclipse.core.runtime.CoreException;
31
import org.eclipse.core.runtime.CoreException;
34
import org.eclipse.core.runtime.NullProgressMonitor;
32
import org.eclipse.core.runtime.NullProgressMonitor;
35
import org.eclipse.core.runtime.Path;
36
import org.eclipse.osgi.util.NLS;
33
import org.eclipse.osgi.util.NLS;
37
import org.eclipse.pde.api.tools.internal.IApiCoreConstants;
38
import org.eclipse.pde.api.tools.internal.IApiXmlConstants;
34
import org.eclipse.pde.api.tools.internal.IApiXmlConstants;
39
import org.eclipse.pde.api.tools.internal.builder.BaseApiAnalyzer;
35
import org.eclipse.pde.api.tools.internal.builder.BaseApiAnalyzer;
40
import org.eclipse.pde.api.tools.internal.builder.BuildContext;
36
import org.eclipse.pde.api.tools.internal.builder.BuildContext;
41
import org.eclipse.pde.api.tools.internal.model.StubApiComponent;
37
import org.eclipse.pde.api.tools.internal.model.StubApiComponent;
42
import org.eclipse.pde.api.tools.internal.problems.ApiProblemFactory;
38
import org.eclipse.pde.api.tools.internal.problems.ApiProblemFactory;
43
import org.eclipse.pde.api.tools.internal.problems.ApiProblemFilter;
44
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
39
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
45
import org.eclipse.pde.api.tools.internal.provisional.IApiFilterStore;
40
import org.eclipse.pde.api.tools.internal.provisional.IApiFilterStore;
46
import org.eclipse.pde.api.tools.internal.provisional.IApiMarkerConstants;
41
import org.eclipse.pde.api.tools.internal.provisional.IApiMarkerConstants;
Lines 48-352 Link Here
48
import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline;
43
import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline;
49
import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent;
44
import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent;
50
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem;
45
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem;
51
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblemFilter;
52
import org.eclipse.pde.api.tools.internal.util.FilteredElements;
46
import org.eclipse.pde.api.tools.internal.util.FilteredElements;
53
import org.eclipse.pde.api.tools.internal.util.Util;
47
import org.eclipse.pde.api.tools.internal.util.Util;
54
import org.w3c.dom.DOMException;
48
import org.w3c.dom.DOMException;
55
import org.w3c.dom.Document;
49
import org.w3c.dom.Document;
56
import org.w3c.dom.Element;
50
import org.w3c.dom.Element;
57
import org.w3c.dom.NodeList;
58
51
59
/**
52
/**
60
 * Ant task to run the API tool verification during Eclipse build.
53
 * Ant task to run the API tool verification during Eclipse build.
61
 */
54
 */
62
public class APIToolsAnalysisTask extends CommonUtilsTask {
55
public class APIToolsAnalysisTask extends CommonUtilsTask {
63
	/**
56
	
64
	 * This filter store is only used to filter problem using existing filters.
65
	 * It doesn't add or remove any filters.
66
	 */
67
	private static class AntFilterStore implements IApiFilterStore {
68
		private static final String GLOBAL = "!global!"; //$NON-NLS-1$
69
		private static int loadIntegerAttribute(Element element, String name) {
70
			String value = element.getAttribute(name);
71
			if(value.length() == 0) {
72
				return -1;
73
			}
74
			try {
75
				int number = Integer.parseInt(value);
76
				return number;
77
			}
78
			catch(NumberFormatException nfe) {}
79
			return -1;
80
		}
81
		private boolean debug;
82
83
		private Map fFilterMap;
84
85
		public AntFilterStore(boolean debug, String filtersRoot, String componentID) {
86
			this.initialize(filtersRoot, componentID);
87
		}
88
89
		public void addFiltersFor(IApiProblem[] problems) {
90
			// do nothing
91
		}
92
93
		public void addFilters(IApiProblemFilter[] filters) {
94
			// do nothing
95
		}
96
97
		private boolean argumentsEquals(String[] problemMessageArguments,
98
				String[] filterProblemMessageArguments) {
99
			// filter problems message arguments are always simple name
100
			// problem message arguments are fully qualified name outside the IDE
101
			int length = problemMessageArguments.length;
102
			if (length == filterProblemMessageArguments.length) {
103
				for (int i = 0; i < length; i++) {
104
					String problemMessageArgument = problemMessageArguments[i];
105
					String filterProblemMessageArgument = filterProblemMessageArguments[i];
106
					if (problemMessageArgument.equals(filterProblemMessageArgument)) {
107
						continue;
108
					}
109
					int index = problemMessageArgument.lastIndexOf('.');
110
					int filterProblemIndex = filterProblemMessageArgument.lastIndexOf('.');
111
					if (index == -1) {
112
						if (filterProblemIndex == -1) {
113
							return false; // simple names should match
114
						}
115
						if (filterProblemMessageArgument.substring(filterProblemIndex + 1).equals(problemMessageArgument)) {
116
							continue;
117
						} else {
118
							return false;
119
						}
120
					} else if (filterProblemIndex != -1) {
121
						return false; // fully qualified name should match
122
					} else {
123
						if (problemMessageArgument.substring(index + 1).equals(filterProblemMessageArgument)) {
124
							continue;
125
						} else {
126
							return false;
127
						}
128
					}
129
				}
130
				return true;
131
			}
132
			return false;
133
		}
134
135
		public void dispose() {
136
			// do nothing
137
		}
138
139
		public IApiProblemFilter[] getFilters(IResource resource) {
140
			return null;
141
		}
142
143
		public IResource[] getResources() {
144
			return null;
145
		}
146
147
		/**
148
		 * Initialize the filter store using the given component id
149
		 */
150
		private void initialize(String filtersRoot, String componentID) {
151
			if(fFilterMap != null) {
152
				return;
153
			}
154
			if(this.debug) {
155
				System.out.println("null filter map, creating a new one"); //$NON-NLS-1$
156
			}
157
			fFilterMap = new HashMap(5);
158
			String xml = null;
159
			InputStream contents = null;
160
			try {
161
				File filterFileParent = new File(filtersRoot, componentID);
162
				if (!filterFileParent.exists()) {
163
					return;
164
				}
165
				contents = new BufferedInputStream(new FileInputStream(new File(filterFileParent, IApiCoreConstants.API_FILTERS_XML_NAME)));
166
				xml = new String(Util.getInputStreamAsCharArray(contents, -1, IApiCoreConstants.UTF_8));
167
			}
168
			catch(IOException ioe) {}
169
			finally {
170
				if (contents != null) {
171
					try {
172
						contents.close();
173
					} catch(IOException e) {
174
						// ignore
175
					}
176
				}
177
			}
178
			if(xml == null) {
179
				return;
180
			}
181
			Element root = null;
182
			try {
183
				root = Util.parseDocument(xml);
184
			}
185
			catch(CoreException ce) {
186
				ApiPlugin.log(ce);
187
			}
188
			if (root == null) {
189
				return;
190
			}
191
			if (!root.getNodeName().equals(IApiXmlConstants.ELEMENT_COMPONENT)) {
192
				return;
193
			}
194
			String component = root.getAttribute(IApiXmlConstants.ATTR_ID);
195
			if(component.length() == 0) {
196
				return;
197
			}
198
			String versionValue = root.getAttribute(IApiXmlConstants.ATTR_VERSION);
199
			int version = 0;
200
			if(versionValue.length() != 0) {
201
				try {
202
					version = Integer.parseInt(versionValue);
203
				} catch (NumberFormatException e) {
204
					// ignore
205
				}
206
			}
207
			if (version < 2) {
208
				// we discard all filters since there is no way to retrieve the type name
209
				return;
210
			}
211
			NodeList resources = root.getElementsByTagName(IApiXmlConstants.ELEMENT_RESOURCE);
212
			ArrayList newfilters = new ArrayList();
213
			ArrayList comments = new ArrayList();
214
			for(int i = 0; i < resources.getLength(); i++) {
215
				Element element = (Element) resources.item(i);
216
				String typeName = element.getAttribute(IApiXmlConstants.ATTR_TYPE);
217
				if (typeName.length() == 0) {
218
					// if there is no type attribute, an empty string is returned
219
					typeName = null;
220
				}
221
				String path = element.getAttribute(IApiXmlConstants.ATTR_PATH);
222
				NodeList filters = element.getElementsByTagName(IApiXmlConstants.ELEMENT_FILTER);
223
				for(int j = 0; j < filters.getLength(); j++) {
224
					element = (Element) filters.item(j);
225
					int id = loadIntegerAttribute(element, IApiXmlConstants.ATTR_ID);
226
					if(id <= 0) {
227
						continue;
228
					}
229
					String[] messageargs = null;
230
					NodeList elements = element.getElementsByTagName(IApiXmlConstants.ELEMENT_PROBLEM_MESSAGE_ARGUMENTS);
231
					if (elements.getLength() != 1) continue;
232
					Element messageArguments = (Element) elements.item(0);
233
					NodeList arguments = messageArguments.getElementsByTagName(IApiXmlConstants.ELEMENT_PROBLEM_MESSAGE_ARGUMENT);
234
					int length = arguments.getLength();
235
					messageargs = new String[length];
236
					String comment = element.getAttribute(IApiXmlConstants.ATTR_COMMENT);
237
					comments.add((comment.length() < 1 ? null : comment));
238
					for (int k = 0; k < length; k++) {
239
						Element messageArgument = (Element) arguments.item(k);
240
						messageargs[k] = messageArgument.getAttribute(IApiXmlConstants.ATTR_VALUE);
241
					}
242
					newfilters.add(ApiProblemFactory.newApiProblem(path, typeName, messageargs, null, null, -1, -1, -1, id));
243
				}
244
			}
245
			internalAddFilters(componentID, (IApiProblem[]) newfilters.toArray(new IApiProblem[newfilters.size()]),
246
					(String[]) comments.toArray(new String[comments.size()]));
247
			newfilters.clear();
248
		}
249
250
		/**
251
		 * Internal use method that allows auto-persisting of the filter file to be turned on or off
252
		 * @param problems the problems to add the the store
253
		 * @param persist if the filters should be auto-persisted after they are added
254
		 */
255
		private void internalAddFilters(String componentID, IApiProblem[] problems, String[] comments) {
256
			if(problems == null) {
257
				if(this.debug) {
258
					System.out.println("null problems array not addding filters"); //$NON-NLS-1$
259
				}
260
				return;
261
			}
262
			for(int i = 0; i < problems.length; i++) {
263
				IApiProblem problem = problems[i];
264
				IApiProblemFilter filter = new ApiProblemFilter(componentID, problem, comments[i]);
265
				String typeName = problem.getTypeName();
266
				if (typeName == null) {
267
					typeName = GLOBAL;
268
				}
269
				Set filters = (Set) fFilterMap.get(typeName);
270
				if(filters == null) {
271
					filters = new HashSet();
272
					fFilterMap.put(typeName, filters);
273
				}
274
				filters.add(filter);
275
			}
276
		}
277
278
		public boolean isFiltered(IApiProblem problem) {
279
			if (this.fFilterMap == null || this.fFilterMap.isEmpty()) return false;
280
			String typeName = problem.getTypeName();
281
			if (typeName == null || typeName.length() == 0) {
282
				typeName = GLOBAL;
283
			}
284
			Set filters = (Set) this.fFilterMap.get(typeName);
285
			if (filters == null) {
286
				return false;
287
			}
288
			for (Iterator iterator = filters.iterator(); iterator.hasNext();) {
289
				IApiProblemFilter filter = (IApiProblemFilter) iterator.next();
290
				if (problem.getCategory() == IApiProblem.CATEGORY_USAGE) {
291
					// write our own matching implementation
292
					return matchUsageProblem(filter.getUnderlyingProblem(), problem);
293
				} else if (matchFilters(filter.getUnderlyingProblem(), problem)) {
294
					return true;
295
				}
296
			}
297
			return false;
298
		}
299
300
		private boolean matchFilters(IApiProblem filterProblem, IApiProblem problem) {
301
			if (problem.getId() == filterProblem.getId() && argumentsEquals(problem.getMessageArguments(), filterProblem.getMessageArguments())) {
302
				String typeName = problem.getTypeName();
303
				String filteredProblemTypeName = filterProblem.getTypeName();
304
				if (typeName == null) {
305
					if (filteredProblemTypeName != null) {
306
						return false;
307
					}
308
					return true;
309
				} else if (filteredProblemTypeName == null) {
310
					return false;
311
				}
312
				return typeName.equals(filteredProblemTypeName);
313
			}
314
			return false;
315
		}
316
317
		private boolean matchUsageProblem(IApiProblem filterProblem, IApiProblem problem) {
318
			if (problem.getId() == filterProblem.getId()) {
319
				// check arguments
320
				String problemPath = problem.getResourcePath();
321
				String filterProblemPath = filterProblem.getResourcePath();
322
				if (problemPath == null) {
323
					if (filterProblemPath != null) {
324
						return false;
325
					}
326
				} else if (filterProblemPath == null) {
327
					return false;
328
				} else if (!new Path(problemPath).equals(new Path(filterProblemPath))) {
329
					return false;
330
				}
331
				String problemTypeName = problem.getTypeName();
332
				String filterProblemTypeName = filterProblem.getTypeName();
333
				if (problemTypeName == null) {
334
					if (filterProblemTypeName != null) {
335
						return false;
336
					}
337
				} else if (filterProblemTypeName == null) {
338
					return false;
339
				} else if (!problemTypeName.equals(filterProblemTypeName)) {
340
					return false;
341
				}
342
				return argumentsEquals(problem.getMessageArguments(), filterProblem.getMessageArguments());
343
			}
344
			return false;
345
		}
346
		public boolean removeFilters(IApiProblemFilter[] filters) {
347
			return false;
348
		}
349
	}
350
	private static class Summary {
57
	private static class Summary {
351
		List apiBundleVersionProblems = new ArrayList();
58
		List apiBundleVersionProblems = new ArrayList();
352
		List apiCompatibilityProblems = new ArrayList();
59
		List apiCompatibilityProblems = new ArrayList();
(-)a/apitools/org.eclipse.pde.api.tools/src_ant/org/eclipse/pde/api/tools/internal/tasks/AntFilterStore.java (+104 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2012 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.pde.api.tools.internal.tasks;
12
13
import java.io.BufferedInputStream;
14
import java.io.File;
15
import java.io.FileInputStream;
16
import java.io.IOException;
17
import java.io.InputStream;
18
import java.util.HashMap;
19
import java.util.HashSet;
20
import java.util.Set;
21
22
import org.eclipse.pde.api.tools.internal.FilterStore;
23
import org.eclipse.pde.api.tools.internal.IApiCoreConstants;
24
import org.eclipse.pde.api.tools.internal.problems.ApiProblemFilter;
25
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem;
26
import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblemFilter;
27
28
/**
29
 * This filter store is only used to filter problem using existing filters.
30
 * It doesn't add or remove any filters.
31
 */
32
public class AntFilterStore extends FilterStore {
33
34
	private boolean debug;
35
	String fComponentId = null;
36
	String fFiltersRoot = null;
37
	
38
	/**
39
	 * Constructor
40
	 * @param debug
41
	 * @param filtersRoot
42
	 * @param componentID
43
	 */
44
	public AntFilterStore(boolean debug, String filtersRoot, String componentID) {
45
		fComponentId = componentID;
46
		fFiltersRoot = filtersRoot;
47
	}
48
49
	/* (non-Javadoc)
50
	 * @see org.eclipse.pde.api.tools.internal.FilterStore#initializeApiFilters()
51
	 */
52
	protected synchronized void initializeApiFilters() {
53
		if(fFilterMap != null) {
54
			return;
55
		}
56
		if(this.debug) {
57
			System.out.println("null filter map, creating a new one"); //$NON-NLS-1$
58
		}
59
		fFilterMap = new HashMap(5);
60
		InputStream contents = null;
61
		try {
62
			File filterFileParent = new File(fFiltersRoot, fComponentId);
63
			if (!filterFileParent.exists()) {
64
				return;
65
			}
66
			contents = new BufferedInputStream(new FileInputStream(new File(filterFileParent, IApiCoreConstants.API_FILTERS_XML_NAME)));
67
			readFilterFile(contents);
68
		}
69
		catch(IOException ioe) {
70
		}
71
		finally {
72
			if (contents != null) {
73
				try {
74
					contents.close();
75
				} catch(IOException e) {
76
					// ignore
77
				}
78
			}
79
		}
80
	}
81
	
82
	/* (non-Javadoc)
83
	 * @see org.eclipse.pde.api.tools.internal.FilterStore#internalAddFilters(org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem[], java.lang.String[])
84
	 */
85
	protected void internalAddFilters(IApiProblem[] problems, String[] comments) {
86
		if(problems == null) {
87
			return;
88
		}
89
		for(int i = 0; i < problems.length; i++) {
90
			IApiProblem problem = problems[i];
91
			IApiProblemFilter filter = new ApiProblemFilter(fComponentId, problem, comments[i]);
92
			String typeName = problem.getTypeName();
93
			if (typeName == null) {
94
				typeName = GLOBAL;
95
			}
96
			Set filters = (Set) fFilterMap.get(typeName);
97
			if(filters == null) {
98
				filters = new HashSet();
99
				fFilterMap.put(typeName, filters);
100
			}
101
			filters.add(filter);
102
		}
103
	}
104
}
(-)a/apitools/org.eclipse.pde.api.tools/src_ant/org/eclipse/pde/api/tools/internal/tasks/ApiUseTask.java (+26 lines)
Lines 25-30 Link Here
25
import org.eclipse.osgi.service.resolver.ResolverError;
25
import org.eclipse.osgi.service.resolver.ResolverError;
26
import org.eclipse.osgi.util.NLS;
26
import org.eclipse.osgi.util.NLS;
27
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
27
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
28
import org.eclipse.pde.api.tools.internal.provisional.IApiFilterStore;
28
import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline;
29
import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline;
29
import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent;
30
import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent;
30
import org.eclipse.pde.api.tools.internal.provisional.model.IApiElement;
31
import org.eclipse.pde.api.tools.internal.provisional.model.IApiElement;
Lines 97-102 Link Here
97
	 * </pre>
98
	 * </pre>
98
	 */
99
	 */
99
	private String[] archivePatterns = null;
100
	private String[] archivePatterns = null;
101
	/**
102
	 * Absolute file paths to the filter files to use
103
	 */
104
	private String[] filterPaths = null;
100
	
105
	
101
	/**
106
	/**
102
	 * List of elements excluded from the scope
107
	 * List of elements excluded from the scope
Lines 238-243 Link Here
238
	}
243
	}
239
	
244
	
240
	/**
245
	/**
246
	 * Sets the paths of the filter files to use
247
	 * @param paths
248
	 */
249
	public void setFilterPaths(String paths) {
250
		filterPaths = parsePatterns(paths);
251
	}
252
	
253
	/**
241
	 * @see org.eclipse.pde.api.tools.internal.tasks.UseTask#assertParameters()
254
	 * @see org.eclipse.pde.api.tools.internal.tasks.UseTask#assertParameters()
242
	 */
255
	 */
243
	protected void assertParameters() throws BuildException {
256
	protected void assertParameters() throws BuildException {
Lines 298-303 Link Here
298
					(IApiElement[]) scope.toArray(new IApiElement[scope.size()]), 
311
					(IApiElement[]) scope.toArray(new IApiElement[scope.size()]), 
299
					getSearchFlags());
312
					getSearchFlags());
300
			requestor.setJarPatterns(archivePatterns);
313
			requestor.setJarPatterns(archivePatterns);
314
			requestor.setGlobalFilterStore(getFilterStore(ids));
301
			// override API descriptions as required
315
			// override API descriptions as required
302
			if (apiPatterns != null || internalPatterns != null) {
316
			if (apiPatterns != null || internalPatterns != null) {
303
				// modify API descriptions
317
				// modify API descriptions
Lines 461-466 Link Here
461
	}
475
	}
462
	
476
	
463
	/**
477
	/**
478
	 * Create a global filter store from a group of filter files
479
	 * 
480
	 * @return the new {@link IApiFilterStore} or <code>null</code>
481
	 */
482
	protected IApiFilterStore getFilterStore(Set ids) {
483
		if(filterPaths != null && !ids.isEmpty()) {
484
			//TODO we need to create the filter store
485
		}
486
		return null;
487
	}
488
	
489
	/**
464
	 * Cleans the report location specified by the parameter {@link CommonUtilsTask#reportLocation}
490
	 * Cleans the report location specified by the parameter {@link CommonUtilsTask#reportLocation}
465
	 */
491
	 */
466
	protected void cleanReportLocation() {
492
	protected void cleanReportLocation() {

Return to bug 332772