EMMA Coverage Report (generated Thu Nov 26 15:54:18 CST 2009)
[all classes][org.eclipse.pde.api.tools.internal]

COVERAGE SUMMARY FOR SOURCE FILE [ApiDescriptionProcessor.java]

nameclass, %method, %block, %line, %
ApiDescriptionProcessor.java100% (3/3)89%  (25/28)83%  (1072/1299)83%  (268.4/323)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ApiDescriptionProcessor$DescriptionVisitor100% (1/1)80%  (4/5)65%  (99/153)71%  (30/42)
addStatus (IStatus): void 0%   (0/1)0%   (0/14)0%   (0/4)
getStatus (): IStatus 100% (1/1)24%  (5/21)40%  (2/5)
endVisitElement (IElementDescriptor, IApiAnnotations): void 100% (1/1)64%  (43/67)69%  (11/16)
ApiDescriptionProcessor$DescriptionVisitor (IJavaProject, IApiDescription, Ma... 100% (1/1)100% (29/29)100% (10/10)
visitElement (IElementDescriptor, IApiAnnotations): boolean 100% (1/1)100% (22/22)100% (7/7)
     
class ApiDescriptionProcessor100% (1/1)83%  (10/12)79%  (583/736)79%  (144.4/182)
ApiDescriptionProcessor (): void 0%   (0/1)0%   (0/3)0%   (0/1)
abort (String, Throwable): void 0%   (0/1)0%   (0/13)0%   (0/2)
getVisibility (Element): int 100% (1/1)56%  (19/34)50%  (6/12)
serializeComponentXml (File): String 100% (1/1)60%  (93/156)62%  (19.2/31)
annotateDescriptor (IJavaProject, IApiDescription, IElementDescriptor, Elemen... 100% (1/1)76%  (16/21)80%  (4/5)
getRestrictions (IJavaProject, Element, IElementDescriptor, boolean): int 100% (1/1)82%  (102/124)84%  (26.8/32)
collectTagUpdates (IJavaProject, File, Map): void 100% (1/1)85%  (28/33)88%  (7/8)
annotateMethodSettings (IJavaProject, IApiDescription, IReferenceTypeDescript... 100% (1/1)89%  (50/56)87%  (13/15)
annotateApiSettings (IJavaProject, IApiDescription, String): void 100% (1/1)91%  (107/117)86%  (25/29)
annotateFieldSettings (IJavaProject, IApiDescription, IReferenceTypeDescripto... 100% (1/1)93%  (40/43)92%  (11/12)
processTagUpdates (IType, IReferenceTypeDescriptor, IApiDescription, List, Ma... 100% (1/1)93%  (109/117)91%  (26.4/29)
annotateRestriction (Element, String, int, int): int 100% (1/1)100% (19/19)100% (6/6)
     
class ApiDescriptionProcessor$ASTTagVisitor100% (1/1)100% (11/11)95%  (390/410)95%  (94/99)
collectMissingTags (IApiAnnotations, List, int, int): String [] 100% (1/1)88%  (118/134)90%  (28/31)
containsRestrictionTag (List, String): boolean 100% (1/1)92%  (22/24)83%  (5/6)
visit (TypeDeclaration): boolean 100% (1/1)93%  (27/29)83%  (5/6)
ApiDescriptionProcessor$ASTTagVisitor (List, IApiDescription, ASTRewrite): void 100% (1/1)100% (26/26)100% (9/9)
createNewTagElement (AST, String): TagElement 100% (1/1)100% (8/8)100% (3/3)
endVisit (TypeDeclaration): void 100% (1/1)100% (5/5)100% (2/2)
findDescriptorByName (String, String): IElementDescriptor 100% (1/1)100% (53/53)100% (12/12)
getType (): int 100% (1/1)100% (6/6)100% (1/1)
updateDocNode (IElementDescriptor, BodyDeclaration, int, int): void 100% (1/1)100% (76/76)100% (19/19)
visit (FieldDeclaration): boolean 100% (1/1)100% (30/30)100% (6/6)
visit (MethodDeclaration): boolean 100% (1/1)100% (19/19)100% (4/4)

1/*******************************************************************************
2 * Copyright (c) 2007, 2009 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 *******************************************************************************/
11package org.eclipse.pde.api.tools.internal;
12 
13import java.io.File;
14import java.io.FileInputStream;
15import java.io.IOException;
16import java.io.InputStream;
17import java.util.ArrayList;
18import java.util.HashSet;
19import java.util.Iterator;
20import java.util.List;
21import java.util.Map;
22import java.util.Stack;
23import java.util.zip.ZipEntry;
24import java.util.zip.ZipFile;
25 
26import org.eclipse.core.filebuffers.FileBuffers;
27import org.eclipse.core.filebuffers.ITextFileBuffer;
28import org.eclipse.core.filebuffers.ITextFileBufferManager;
29import org.eclipse.core.filebuffers.LocationKind;
30import org.eclipse.core.resources.IFile;
31import org.eclipse.core.runtime.CoreException;
32import org.eclipse.core.runtime.IPath;
33import org.eclipse.core.runtime.IStatus;
34import org.eclipse.core.runtime.MultiStatus;
35import org.eclipse.core.runtime.NullProgressMonitor;
36import org.eclipse.core.runtime.Path;
37import org.eclipse.core.runtime.Status;
38import org.eclipse.jdt.core.Flags;
39import org.eclipse.jdt.core.ICompilationUnit;
40import org.eclipse.jdt.core.IJavaProject;
41import org.eclipse.jdt.core.IType;
42import org.eclipse.jdt.core.JavaCore;
43import org.eclipse.jdt.core.JavaModelException;
44import org.eclipse.jdt.core.dom.AST;
45import org.eclipse.jdt.core.dom.ASTParser;
46import org.eclipse.jdt.core.dom.ASTVisitor;
47import org.eclipse.jdt.core.dom.BodyDeclaration;
48import org.eclipse.jdt.core.dom.CompilationUnit;
49import org.eclipse.jdt.core.dom.FieldDeclaration;
50import org.eclipse.jdt.core.dom.Javadoc;
51import org.eclipse.jdt.core.dom.MethodDeclaration;
52import org.eclipse.jdt.core.dom.TagElement;
53import org.eclipse.jdt.core.dom.TypeDeclaration;
54import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
55import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
56import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
57import org.eclipse.jface.text.BadLocationException;
58import org.eclipse.jface.text.IDocument;
59import org.eclipse.pde.api.tools.internal.provisional.ApiDescriptionVisitor;
60import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
61import org.eclipse.pde.api.tools.internal.provisional.Factory;
62import org.eclipse.pde.api.tools.internal.provisional.IApiAnnotations;
63import org.eclipse.pde.api.tools.internal.provisional.IApiDescription;
64import org.eclipse.pde.api.tools.internal.provisional.IApiJavadocTag;
65import org.eclipse.pde.api.tools.internal.provisional.RestrictionModifiers;
66import org.eclipse.pde.api.tools.internal.provisional.VisibilityModifiers;
67import org.eclipse.pde.api.tools.internal.provisional.descriptors.IElementDescriptor;
68import org.eclipse.pde.api.tools.internal.provisional.descriptors.IFieldDescriptor;
69import org.eclipse.pde.api.tools.internal.provisional.descriptors.IMethodDescriptor;
70import org.eclipse.pde.api.tools.internal.provisional.descriptors.IPackageDescriptor;
71import org.eclipse.pde.api.tools.internal.provisional.descriptors.IReferenceTypeDescriptor;
72import org.eclipse.pde.api.tools.internal.provisional.scanner.ScannerMessages;
73import org.eclipse.pde.api.tools.internal.util.Signatures;
74import org.eclipse.pde.api.tools.internal.util.Util;
75import org.eclipse.text.edits.TextEdit;
76import org.w3c.dom.Element;
77import org.w3c.dom.NodeList;
78 
79/**
80 * Provides tools for scanning/loading/parsing component.xml files.
81 * 
82 * @since 1.0.0
83 */
84public class ApiDescriptionProcessor {
85 
86        /**
87         * Visits each type, collecting all members before processing the type.
88         */
89        static class DescriptionVisitor extends ApiDescriptionVisitor {
90                
91                /**
92                 * The API description associated with the project. 
93                 */
94                private IApiDescription apiDescription = null;
95                
96                /**
97                 * Java project to resolve types in
98                 */
99                private IJavaProject project = null;
100                
101                /**
102                 * List to collect text edits
103                 */
104                private Map fCollector = null;
105                
106                /**
107                 * Members collected from current type.
108                 */
109                private List members = new ArrayList();
110                
111                /**
112                 * List of exception statuses that occurred, or <code>null</code> if none.
113                 */
114                private List exceptions = null;
115                
116                /**
117                 * Constructs a new visitor to collect tag updates in a java project.
118                 * 
119                 * @param jp project to update
120                 * @param cd project's API description
121                 * @param collector collection to place text edits into
122                 */
123                DescriptionVisitor(IJavaProject jp, IApiDescription cd, Map collector) {
124                        project = jp;
125                        apiDescription = cd;
126                        fCollector = collector;
127                }
128                
129                /* (non-Javadoc)
130                 * @see org.eclipse.pde.api.tools.model.component.ApiDescriptionVisitor#visitElement(org.eclipse.pde.api.tools.model.component.IElementDescriptor, java.lang.String, org.eclipse.pde.api.tools.model.IApiAnnotations)
131                 */
132                public boolean visitElement(IElementDescriptor element, IApiAnnotations description) {
133                        switch(element.getElementType()) {
134                                case IElementDescriptor.PACKAGE: {
135                                        return true;
136                                }
137                                case IElementDescriptor.TYPE: {
138                                        members.clear(); 
139                                        members.add(element);
140                                        return true;
141                                }
142                                default: {
143                                        members.add(element);
144                                }
145                        }
146                        return false;
147                }
148 
149                /* (non-Javadoc)
150                 * @see org.eclipse.pde.api.tools.model.component.ApiDescriptionVisitor#endVisitElement(org.eclipse.pde.api.tools.model.component.IElementDescriptor, java.lang.String, org.eclipse.pde.api.tools.model.IApiAnnotations)
151                 */
152                public void endVisitElement(IElementDescriptor element, IApiAnnotations description) {
153                        if (element.getElementType() == IElementDescriptor.TYPE) {
154                                IReferenceTypeDescriptor refType = (IReferenceTypeDescriptor) element;
155                                try {
156                                        IReferenceTypeDescriptor topLevelType = refType.getEnclosingType();
157                                        while (topLevelType != null) {
158                                                refType = topLevelType;
159                                                topLevelType = refType.getEnclosingType();
160                                        }
161                                        IType type = project.findType(refType.getQualifiedName(), new NullProgressMonitor());
162                                        if(type != null) {
163                                                processTagUpdates(type, refType, apiDescription, members, fCollector);
164                                        }
165                                } catch (CoreException e) {
166                                        addStatus(e.getStatus());
167                                } catch (BadLocationException e) {
168                                        addStatus(new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, 
169                                                        ScannerMessages.ComponentXMLScanner_0 + element.toString(),e));
170                                }
171                                members.clear();
172                        }
173                }
174                
175                /**
176                 * Adds a status to the current listing of messages
177                 * @param status
178                 */
179                private void addStatus(IStatus status) {
180                        if (exceptions == null) {
181                                exceptions = new ArrayList();
182                        }
183                        exceptions.add(status);
184                }
185                
186                /**
187                 * Returns the status of processing the project. Status is OK
188                 * if no errors occurred.
189                 * 
190                 * @return status
191                 */
192                public IStatus getStatus() {
193                        if (exceptions == null) {
194                                return Status.OK_STATUS;
195                        }
196                        return new MultiStatus(ApiPlugin.PLUGIN_ID, 0, 
197                                        (IStatus[]) exceptions.toArray(new IStatus[exceptions.size()]),
198                                        ScannerMessages.ComponentXMLScanner_1, null);
199                }
200                
201        }
202        
203        /**
204         * Visitor used for finding the nodes to update the javadoc tags for, if needed
205         */
206        static class ASTTagVisitor extends ASTVisitor {
207                private List apis = null;
208                private IApiDescription description = null;
209                private ASTRewrite rewrite = null;
210                private Stack typeStack;
211                /**
212                 * Constructor
213                 * @param APIs a listing of {@link IElementDescriptor}s that we care about for this visit
214                 */
215                public ASTTagVisitor(List apis, IApiDescription description, ASTRewrite rewrite) {
216                        this.apis = apis;
217                        this.description = description;
218                        this.rewrite = rewrite;
219                        typeStack = new Stack();
220                }
221 
222                /* (non-Javadoc)
223                 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.TypeDeclaration)
224                 */
225                public boolean visit(TypeDeclaration node) {
226                        int type = IApiJavadocTag.TYPE_CLASS;
227                        if (node.isInterface()) {
228                                type = IApiJavadocTag.TYPE_INTERFACE;
229                        }
230                        typeStack.push(new Integer(type));
231                        updateDocNode(findDescriptorByName(node.getName().getFullyQualifiedName(), null), node, getType(), IApiJavadocTag.MEMBER_NONE);
232                        return true;
233                }
234                
235                /* (non-Javadoc)
236                 * @see org.eclipse.jdt.core.dom.ASTVisitor#endVisit(org.eclipse.jdt.core.dom.TypeDeclaration)
237                 */
238                public void endVisit(TypeDeclaration node) {
239                        typeStack.pop();
240                }
241                
242                /**
243                 * Returns the kind of type being visited.
244                 * 
245                 * @return <code>TYPE_CLASS</code> or <code>TYPE_INTERFACE</code>
246                 */
247                private int getType() {
248                        return ((Integer)(typeStack.peek())).intValue();
249                }
250 
251                /* (non-Javadoc)
252                 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.FieldDeclaration)
253                 */
254                public boolean visit(FieldDeclaration node) {
255                        List fields = node.fragments();
256                        VariableDeclarationFragment fragment = null;
257                        for(Iterator iter = fields.iterator(); iter.hasNext();) {
258                                fragment = (VariableDeclarationFragment) iter.next();
259                                updateDocNode(findDescriptorByName(fragment.getName().getFullyQualifiedName(), null), node, getType(), IApiJavadocTag.MEMBER_FIELD);
260                        }
261                        return false;
262                }
263                /* (non-Javadoc)
264                 * @see org.eclipse.jdt.core.dom.ASTVisitor#visit(org.eclipse.jdt.core.dom.MethodDeclaration)
265                 */
266                public boolean visit(MethodDeclaration node) {
267                        String signature = Signatures.getMethodSignatureFromNode(node);
268                        if(signature != null) {
269                                updateDocNode(findDescriptorByName(node.getName().getFullyQualifiedName(), signature), node, getType(), IApiJavadocTag.MEMBER_METHOD);
270                        }
271                        return false;
272                }
273                /**
274                 * Updates the specified javadoc node if needed, creates a new doc node if one is not present
275                 * @param element the element to get API information from 
276                 * @param docnode the doc node to update
277                 * @param type one of <code>CLASS</code> or <code>INTERFACE</code>
278              * @param member one of <code>METHOD</code> or <code>FIELD</code> or <code>NONE</code>
279                 */
280                private void updateDocNode(IElementDescriptor element, BodyDeclaration body, int type, int member) {
281                        if(element != null) {
282                                //check for missing tags first, might not need to do any work
283                                IApiAnnotations api = description.resolveAnnotations(element);
284                                if(api != null) {
285                                        Javadoc docnode = body.getJavadoc();
286                                        AST ast = body.getAST();
287                                        boolean newnode = docnode == null;
288                                        if(docnode == null) {
289                                                docnode = ast.newJavadoc();
290                                        }
291                                        String[] missingtags = collectMissingTags(api, docnode.tags(), type, member);
292                                        if(missingtags.length == 0) {
293                                                return;
294                                        }
295                                        else if(newnode) {
296                                                //we do not want to create a new empty Javadoc node in
297                                                //the AST if there are no missing tags
298                                                rewrite.set(body, body.getJavadocProperty(), docnode, null);
299                                        }
300                                        ListRewrite lrewrite = rewrite.getListRewrite(docnode, Javadoc.TAGS_PROPERTY);
301                                        TagElement newtag = null;
302                                        for(int i = 0; i < missingtags.length; i++) {
303                                                newtag = createNewTagElement(ast, missingtags[i]);
304                                                lrewrite.insertLast(newtag, null);
305                                        }
306                                }
307                        }
308                }
309                /**
310                 * Creates a new {@link TagElement} against the specified {@link AST} and returns it
311                 * @param ast the {@link AST} to create the {@link TagElement} against
312                 * @param tagname the name of the new tag
313                 * @return a new {@link TagElement} with the given name
314                 */
315                private TagElement createNewTagElement(AST ast, String tagname) {
316                        TagElement newtag = ast.newTagElement();
317                        newtag.setTagName(tagname);
318                        return newtag;
319                }
320                /**
321                 * Collects the missing javadoc tags from based on the given listing of {@link TagElement}s
322                 * @param api
323                 * @param tags
324                 * @param type one of <code>CLASS</code> or <code>INTERFACE</code>
325                 * @param member one of <code>METHOD</code> or <code>FIELD</code> or <code>NONE</code>
326                 * @return an array of the missing {@link TagElement}s or an empty array, never <code>null</code>
327                 */
328                private String[] collectMissingTags(IApiAnnotations api, List tags, int type, int member) {
329                        int res = api.getRestrictions();
330                        ArrayList missing = new ArrayList();
331                        JavadocTagManager jtm = ApiPlugin.getJavadocTagManager();
332                        switch(member) {
333                                case IApiJavadocTag.MEMBER_FIELD :
334                                        if(RestrictionModifiers.isReferenceRestriction(res)) {
335                                                if(!containsRestrictionTag(tags, "@noreference")) { //$NON-NLS-1$
336                                                        IApiJavadocTag tag = jtm.getTag(IApiJavadocTag.NO_REFERENCE_TAG_ID);
337                                                        missing.add(tag.getCompleteTag(type, member));
338                                                }
339                                        }
340                                        break;
341                                case IApiJavadocTag.MEMBER_METHOD :
342                                        if(RestrictionModifiers.isReferenceRestriction(res)) {
343                                                if(!containsRestrictionTag(tags, "@noreference")) { //$NON-NLS-1$
344                                                        IApiJavadocTag tag = jtm.getTag(IApiJavadocTag.NO_REFERENCE_TAG_ID);
345                                                        missing.add(tag.getCompleteTag(type, member));
346                                                }
347                                        }
348                                        if(RestrictionModifiers.isOverrideRestriction(res)) {
349                                                if(!containsRestrictionTag(tags, "@nooverride")) { //$NON-NLS-1$
350                                                        IApiJavadocTag tag = jtm.getTag(IApiJavadocTag.NO_OVERRIDE_TAG_ID);
351                                                        missing.add(tag.getCompleteTag(type, member));
352                                                }
353                                        }
354                                        break;
355                                case IApiJavadocTag.MEMBER_NONE :
356                                        if(RestrictionModifiers.isImplementRestriction(res)) {
357                                                if(!containsRestrictionTag(tags, "@noimplement")) { //$NON-NLS-1$
358                                                        IApiJavadocTag tag = jtm.getTag(IApiJavadocTag.NO_IMPLEMENT_TAG_ID);
359                                                        missing.add(tag.getCompleteTag(type, member));
360                                                }
361                                        }
362                                        if(RestrictionModifiers.isInstantiateRestriction(res)) {
363                                                if(!containsRestrictionTag(tags, "@noinstantiate")) { //$NON-NLS-1$
364                                                        IApiJavadocTag tag = jtm.getTag(IApiJavadocTag.NO_INSTANTIATE_TAG_ID);
365                                                        missing.add(tag.getCompleteTag(type, member));
366                                                }
367                                        }
368                                        if(RestrictionModifiers.isExtendRestriction(res)) {
369                                                if(!containsRestrictionTag(tags, "@noextend")) { //$NON-NLS-1$
370                                                        IApiJavadocTag tag = jtm.getTag(IApiJavadocTag.NO_EXTEND_TAG_ID);
371                                                        missing.add(tag.getCompleteTag(type, member));
372                                                }
373                                        }
374                        }
375                        return (String[]) missing.toArray(new String[missing.size()]);
376                }
377                /**
378                 * Determines if the specified tag appears in the {@link TagElement} listing given
379                 * @param tags
380                 * @param tag
381                 * @return true if the listing of {@link TagElement}s contains the given tag
382                 */
383                private boolean containsRestrictionTag(List tags, String tag) {
384                        TagElement tagelement = null;
385                        for(int i = 0; i < tags.size(); i++) {
386                                tagelement = (TagElement) tags.get(i);
387                                if(tag.equals(tagelement.getTagName())) {
388                                        return true;
389                                }
390                        }
391                        return false;
392                }
393                /**
394                 * Finds the {@link IElementDescriptor} that matches the specified name and signature
395                 * @param name
396                 * @param signature
397                 * @return the matching {@link IElementDescriptor} or <code>null</code> 
398                 */
399                private IElementDescriptor findDescriptorByName(String name, String signature) {
400                        IElementDescriptor desc = null;
401                        for(int i = 0; i < apis.size(); i++) {
402                                desc = (IElementDescriptor) apis.get(i);
403                                switch(desc.getElementType()) {
404                                        case IElementDescriptor.TYPE: {
405                                                if(((IReferenceTypeDescriptor)desc).getName().equals(name)) {
406                                                        return desc;
407                                                }
408                                                break;
409                                        }
410                                        case IElementDescriptor.METHOD: {
411                                                IMethodDescriptor method = (IMethodDescriptor) desc;
412                                                if(method.getName().equals(name) && method.getSignature().equals(signature)) {
413                                                        return desc;
414                                                }
415                                                break;
416                                        }
417                                        case IElementDescriptor.FIELD: {
418                                                if(((IFieldDescriptor)desc).getName().equals(name)) {
419                                                        return desc;
420                                                }
421                                                break;
422                                        }
423                                }
424                        }
425                        return null;
426                }
427        }
428        
429        /**
430         * Constructor
431         * can not be instantiated directly
432         */
433        private ApiDescriptionProcessor() {}
434        
435        /**
436         * Parses a component XML into a string. The location may be a jar, directory containing the component.xml file, or 
437         * the component.xml file itself
438         * 
439         * @param location root location of the component.xml file, or the component.xml file itself
440         * @return component XML as a string or <code>null</code> if none
441         * @throws IOException if unable to parse
442         */
443        public static String serializeComponentXml(File location) {
444                if(location.exists()) {
445                        ZipFile jarFile = null;
446                        InputStream stream = null;
447                        try {
448                                String extension = new Path(location.getName()).getFileExtension();
449                                if (extension != null && extension.equals("jar") && location.isFile()) { //$NON-NLS-1$
450                                        jarFile = new ZipFile(location, ZipFile.OPEN_READ);
451                                        ZipEntry manifestEntry = jarFile.getEntry(IApiCoreConstants.COMPONENT_XML_NAME);
452                                        if (manifestEntry != null) {
453                                                stream = jarFile.getInputStream(manifestEntry);
454                                        }
455                                } else if(location.isDirectory()) {
456                                        File file = new File(location, IApiCoreConstants.COMPONENT_XML_NAME);
457                                        if (file.exists()) {
458                                                stream = new FileInputStream(file);
459                                        }
460                                }
461                                else if(location.isFile()) {
462                                        if(location.getName().equals(IApiCoreConstants.COMPONENT_XML_NAME)) {
463                                                stream = new FileInputStream(location);
464                                        }
465                                }
466                                if(stream != null) {
467                                                return new String(Util.getInputStreamAsCharArray(stream, -1, IApiCoreConstants.UTF_8));
468                                }
469                        } catch(IOException e) {
470                                ApiPlugin.log(e);
471                        } finally {
472                                try {
473                                        if (stream != null) {
474                                                stream.close();
475                                        }
476                                } catch (IOException e) {
477                                        ApiPlugin.log(e);
478                                }
479                                try {
480                                        if (jarFile != null) {
481                                                jarFile.close();
482                                        }
483                                } catch (IOException e) {
484                                        ApiPlugin.log(e);
485                                }
486                        }
487                }
488                return null;
489        }
490        
491        /**
492         * This method updates the javadoc for members of the specified java source files with information
493         * retrieved from the the specified component.xml file.
494         * @param project the java project to update
495         * @param componentxml the component.xml file to update from
496         * @param collector
497         * @throws CoreException
498         * @throws IOException
499         */
500        public static void collectTagUpdates(IJavaProject project, File componentxml, Map collector) throws CoreException, IOException {
501                IApiDescription description = new ApiDescription(null);
502                annotateApiSettings(project, description, serializeComponentXml(componentxml));
503                //visit the types
504                DescriptionVisitor visitor = new DescriptionVisitor(project, description, collector);
505                description.accept(visitor, null);
506                IStatus status = visitor.getStatus();
507                if (!status.isOK()) {
508                        throw new CoreException(status);
509                }
510        }
511        
512        /**
513         * Given the type, the parent type descriptor and an annotated description, update
514         * the javadoc comments for the type and all members of the type found in the description.
515         * @param type
516         * @param desc
517         * @param description
518         * @param members members with API annotations
519         * @param collector
520         * @throws CoreException
521         * @throws BadLocationException
522         */
523        static void processTagUpdates(IType type, IReferenceTypeDescriptor desc, IApiDescription description, List members, Map collector) throws CoreException, BadLocationException {
524                ASTParser parser = ASTParser.newParser(AST.JLS3);
525                ICompilationUnit cunit = type.getCompilationUnit();
526                if(cunit != null) {
527                        parser.setSource(cunit);
528                        Map options = cunit.getJavaProject().getOptions(true);
529                        options.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED);
530                        parser.setCompilerOptions(options);
531                        CompilationUnit cast = (CompilationUnit) parser.createAST(new NullProgressMonitor());
532                        cast.recordModifications();
533                        ASTRewrite rewrite = ASTRewrite.create(cast.getAST());
534                        ASTTagVisitor visitor = new ASTTagVisitor(members, description, rewrite);
535                        cast.accept(visitor);
536                        ITextFileBufferManager bm = FileBuffers.getTextFileBufferManager(); 
537                        IPath path = cast.getJavaElement().getPath();
538                        try {
539                                bm.connect(path, LocationKind.IFILE, null);
540                                ITextFileBuffer tfb = bm.getTextFileBuffer(path, LocationKind.IFILE);
541                                IDocument document = tfb.getDocument();
542                                TextEdit edit = rewrite.rewriteAST(document, null);
543                                if(edit.getChildrenSize() > 0 || edit.getLength() != 0) {
544                                        IFile file = (IFile) cunit.getUnderlyingResource();
545                                        HashSet edits = (HashSet) collector.get(file);
546                                        if(edits == null) {
547                                                edits = new HashSet(3);
548                                                collector.put(file, edits);
549                                        }
550                                        edits.add(edit);
551                                }
552                        } finally {
553                                bm.disconnect(path, LocationKind.IFILE, null);
554                        }
555                }
556        }
557        
558        /**
559         * Throws an exception with the given message and underlying exception.
560         * 
561         * @param message error message
562         * @param exception underlying exception, or <code>null</code>
563         * @throws CoreException
564         */
565        private static void abort(String message, Throwable exception) throws CoreException {
566                IStatus status = new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, message, exception);
567                throw new CoreException(status);
568        }
569 
570        /**
571         * Parses the given xml document (in string format), and annotates the specified 
572         * {@link IApiDescription} with {@link IPackageDescriptor}s, {@link IReferenceTypeDescriptor}s, {@link IMethodDescriptor}s
573         * and {@link IFieldDescriptor}s.
574         * 
575         * @param settings API settings to annotate
576         * @param xml XML used to generate settings
577         * @throws CoreException 
578         */
579        public static void annotateApiSettings(IJavaProject project, IApiDescription settings, String xml) throws CoreException {
580                Element root = null;
581                try {
582                        root = Util.parseDocument(xml);
583                }
584                catch(CoreException ce) {
585                        abort("Failed to parse API description xml file", ce); //$NON-NLS-1$
586                }
587                if (!root.getNodeName().equals(IApiXmlConstants.ELEMENT_COMPONENT)) {
588                        abort(ScannerMessages.ComponentXMLScanner_0, null); 
589                }
590                String version = root.getAttribute(IApiXmlConstants.ATTR_VERSION);
591                ApiDescription desc = (ApiDescription) settings;
592                desc.setEmbeddedVersion(version);
593                //TODO for now this compares to 1.2, since the change from 1.1 -> 1.2 denotes the 
594                //@noextend change, not 1.1 -> current version
595                boolean earlierversion = desc.compareEmbeddedVersionTo("1.2") == 1; //$NON-NLS-1$
596                NodeList packages = root.getElementsByTagName(IApiXmlConstants.ELEMENT_PACKAGE);
597                NodeList types = null;
598                IPackageDescriptor packdesc = null;
599                Element type = null;
600                for (int i = 0; i < packages.getLength(); i++) {
601                        Element pkg = (Element) packages.item(i);
602                        // package visibility comes from the MANIFEST.MF
603                        String pkgName = pkg.getAttribute(IApiXmlConstants.ATTR_NAME);
604                        packdesc = Factory.packageDescriptor(pkgName);
605                        types = pkg.getElementsByTagName(IApiXmlConstants.ELEMENT_TYPE);
606                        for (int j = 0; j < types.getLength(); j++) {
607                                type = (Element) types.item(j);
608                                String name = type.getAttribute(IApiXmlConstants.ATTR_NAME);
609                                if (name.length() == 0) {
610                                        abort("Missing type name", null); //$NON-NLS-1$
611                                }
612                                IReferenceTypeDescriptor typedesc = packdesc.getType(name); 
613                                annotateDescriptor(project, settings, typedesc, type, earlierversion);
614                                annotateMethodSettings(project, settings, typedesc, type, earlierversion);
615                                annotateFieldSettings(project, settings, typedesc, type, earlierversion);
616                        }
617                }
618        }
619        
620        /**
621         * Annotates the backing {@link IApiDescription} from the given {@link Element}, by adding the visibility
622         * and restriction attributes to the specified {@link IElementDescriptor}
623         * 
624         * @param settings the settings to annotate
625         * @param descriptor the current descriptor context
626         * @param element the current element to annotate from
627         * @param earlierversion if the version read from XML is older than the current tooling version
628         */
629        private static void annotateDescriptor(IJavaProject project, IApiDescription settings, IElementDescriptor descriptor, Element element, boolean earlierversion) {
630                int typeVis = getVisibility(element);
631                if (typeVis != -1) {
632                        settings.setVisibility(descriptor, typeVis);
633                }
634                settings.setRestrictions(descriptor, getRestrictions(project, element, descriptor, earlierversion));
635        }
636        
637        /**
638         * Returns restriction settings described in the given element.
639         * 
640         * @param project the {@link IJavaProject} context
641         * @param element XML element
642         * @param descriptor the {@link IElementDescriptor} to get the restrictions for
643         * @param earlierversion if the version read from XML is older than the current tooling version
644         * @return restriction settings
645         */
646        private static int getRestrictions(final IJavaProject project, final Element element, final IElementDescriptor descriptor, boolean earlierversion) {
647                int res = RestrictionModifiers.NO_RESTRICTIONS;
648                if(element.hasAttribute(IApiXmlConstants.ATTR_RESTRICTIONS)) {
649                        res = Integer.parseInt(element.getAttribute(IApiXmlConstants.ATTR_RESTRICTIONS));
650                }
651                else {
652                        switch(descriptor.getElementType()) {
653                                case IElementDescriptor.FIELD: {
654                                        res = annotateRestriction(element, IApiXmlConstants.ATTR_REFERENCE, RestrictionModifiers.NO_REFERENCE, res);
655                                        break;
656                                }
657                                case IElementDescriptor.METHOD: {
658                                        IMethodDescriptor method  = (IMethodDescriptor) descriptor;
659                                        res = annotateRestriction(element, IApiXmlConstants.ATTR_REFERENCE, RestrictionModifiers.NO_REFERENCE, res);
660                                        if(!method.isConstructor()) {
661                                                res = annotateRestriction(element, IApiXmlConstants.ATTR_OVERRIDE, RestrictionModifiers.NO_OVERRIDE, res);
662                                        }
663                                        break;
664                                }
665                                case IElementDescriptor.TYPE: {
666                                        IReferenceTypeDescriptor rtype = (IReferenceTypeDescriptor) descriptor;
667                                        res = annotateRestriction(element, IApiXmlConstants.ATTR_IMPLEMENT, RestrictionModifiers.NO_IMPLEMENT, res);
668                                        if(earlierversion && RestrictionModifiers.isImplementRestriction(res)) {
669                                                res |= RestrictionModifiers.NO_EXTEND;
670                                        }
671                                        res = annotateRestriction(element, IApiXmlConstants.ATTR_EXTEND, RestrictionModifiers.NO_EXTEND, res);
672                                        if(!RestrictionModifiers.isExtendRestriction(res)) {
673                                                res = annotateRestriction(element, IApiXmlConstants.ATTR_SUBCLASS, RestrictionModifiers.NO_EXTEND, res);
674                                        }
675                                        res = annotateRestriction(element, IApiXmlConstants.ATTR_INSTANTIATE, RestrictionModifiers.NO_INSTANTIATE, res);
676                                        IType type = null;
677                                        if (project != null) {
678                                                try {
679                                                        type = project.findType(rtype.getQualifiedName());
680                                                        if (type != null) {
681                                                                if(Flags.isInterface(type.getFlags())) {
682                                                                        res &= ~RestrictionModifiers.NO_INSTANTIATE;
683                                                                }
684                                                                else {
685                                                                        res &= ~RestrictionModifiers.NO_IMPLEMENT;
686                                                                        if(Flags.isFinal(type.getFlags())) {
687                                                                                res &= ~RestrictionModifiers.NO_EXTEND;
688                                                                        }
689                                                                        if(Flags.isAbstract(type.getFlags())) {
690                                                                                res &= ~RestrictionModifiers.NO_INSTANTIATE;
691                                                                        }
692                                                                }
693                                                        }
694                                                } 
695                                                catch (JavaModelException e) {}
696                                        }
697                                        break;
698                                }
699                        }
700                }
701                return res;
702        }
703        
704        /**
705         * Tests if the given restriction exists for the given element
706         * and returns an updated restrictions flag.
707         * 
708         * @param element XML element
709         * @param name attribute to test
710         * @param flag bit mask for attribute
711         * @param res flag to combine with 
712         * @return updated flags
713         */
714        private static int annotateRestriction(Element element, String name, int flag, int res) {
715                String value = element.getAttribute(name);
716                int lres = res;
717                if (value.length() > 0) {
718                        if (!Boolean.valueOf(value).booleanValue()) {
719                                lres = res | flag;
720                        }
721                }
722                return lres;
723        }
724        
725        /**
726         * Returns visibility settings described in the given element or
727         * -1 if none.
728         * 
729         * @param element XML element
730         * @return visibility settings or -1 if none
731         */
732        private static int getVisibility(Element element) {
733                String attribute = element.getAttribute(IApiXmlConstants.ATTR_VISIBILITY);
734                try {
735                        return Integer.parseInt(attribute);
736                }
737                catch(NumberFormatException nfe) {
738                        if ("API".equals(attribute)) { //$NON-NLS-1$
739                                return VisibilityModifiers.API;
740                        }
741                        if ("PRIVATE".equals(attribute)) { //$NON-NLS-1$
742                                return VisibilityModifiers.PRIVATE;
743                        }
744                        if ("PRIVATE_PERMISSABLE".equals(attribute)) { //$NON-NLS-1$
745                                return VisibilityModifiers.PRIVATE_PERMISSIBLE;
746                        }
747                        if ("SPI".equals(attribute)) { //$NON-NLS-1$
748                                return VisibilityModifiers.SPI;
749                        }
750                        return -1;
751                }
752        }
753        
754        /**
755         * Annotates the supplied {@link IApiDescription} from all of the field elements
756         * that are direct children of the specified {@link Element}. {@link IFieldDescriptor}s are created
757         * as needed and added as children of the specified {@link IReferenceTypeDescriptor}.
758         * 
759         * @param settings the {@link IApiDescription} to add the new {@link IFieldDescriptor} to
760         * @param typedesc the containing type descriptor for this field
761         * @param type the parent {@link Element}
762         * @param earlierversion if the version read from XML is older than the current tooling version
763         * @throws CoreException
764         */
765        private static void annotateFieldSettings(IJavaProject project, IApiDescription settings, IReferenceTypeDescriptor typedesc, Element type, boolean earlierversion) throws CoreException {
766                NodeList fields = type.getElementsByTagName(IApiXmlConstants.ELEMENT_FIELD);
767                Element field = null;
768                IFieldDescriptor fielddesc = null;
769                String name = null;
770                for(int i = 0; i < fields.getLength(); i++) {
771                        field = (Element) fields.item(i);
772                        name = field.getAttribute(IApiXmlConstants.ATTR_NAME);
773                        if(name == null) {
774                                abort(ScannerMessages.ComponentXMLScanner_1, null); 
775                        }
776                        fielddesc = typedesc.getField(name);
777                        annotateDescriptor(project, settings, fielddesc, field, earlierversion);
778                }
779        }
780        
781        /**
782         * Annotates the supplied {@link IApiDescription} from all of the method elements
783         * that are direct children of the specified {@link Element}. {@link IMethodDescriptor}s are created
784         * as needed and added as children of the specified {@link IReferenceTypeDescriptor}.
785         * 
786         * @param settings the {@link IApiDescription} to add the new {@link IMethodDescriptor} to 
787         * @param typedesc the containing type descriptor for this method
788         * @param type the parent {@link Element}
789         * @param earlierversion if the version read from XML is older than the current tooling version
790         * @throws CoreException
791         */
792        private static void annotateMethodSettings(IJavaProject project, IApiDescription settings, IReferenceTypeDescriptor typedesc, Element type, boolean earlierversion) throws CoreException {
793                NodeList methods = type.getElementsByTagName(IApiXmlConstants.ELEMENT_METHOD);
794                Element method = null;
795                IMethodDescriptor methoddesc = null;
796                String name, signature;
797                for(int i = 0; i < methods.getLength(); i++) {
798                        method = (Element) methods.item(i);
799                        name = method.getAttribute(IApiXmlConstants.ATTR_NAME);
800                        if(name == null) {
801                                abort(ScannerMessages.ComponentXMLScanner_2, null); 
802                        }
803                        signature = method.getAttribute(IApiXmlConstants.ATTR_SIGNATURE);
804                        if(signature == null) {
805                                abort(ScannerMessages.ComponentXMLScanner_3, null); 
806                        }
807                        // old files might use '.' instead of '/'
808                        signature = signature.replace('.', '/');
809                        methoddesc = typedesc.getMethod(name, signature);
810                        annotateDescriptor(project, settings, methoddesc, method, earlierversion);
811                }
812        }
813}

[all classes][org.eclipse.pde.api.tools.internal]
EMMA 2.0.5312 EclEmma Fix 1 (C) Vladimir Roubtsov