1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.cts.apicoverage;
18 
19 import org.xml.sax.Attributes;
20 import org.xml.sax.SAXException;
21 import org.xml.sax.helpers.DefaultHandler;
22 
23 import java.util.ArrayList;
24 import java.util.List;
25 
26 /**
27  * {@link DefaultHandler} that builds an empty {@link ApiCoverage} object from scanning current.xml.
28  */
29 class CurrentXmlHandler extends DefaultHandler {
30 
31     private String mCurrentPackageName;
32 
33     private String mCurrentClassName;
34 
35     private String mCurrentInterfaceName;
36 
37     private boolean mIgnoreCurrentClass;
38 
39     private String mCurrentMethodName;
40 
41     private String mCurrentMethodReturnType;
42 
43     private boolean mCurrentMethodIsAbstract;
44 
45     private String mCurrentMethodVisibility;
46 
47     private boolean mCurrentMethodStaticMethod;
48 
49     private boolean mCurrentMethodFinalMethod;
50 
51     private boolean mDeprecated;
52 
53 
54     private List<String> mCurrentParameterTypes = new ArrayList<String>();
55 
56     private ApiCoverage mApiCoverage = new ApiCoverage();
57 
getApi()58     public ApiCoverage getApi() {
59         return mApiCoverage;
60     }
61 
62     @Override
startElement(String uri, String localName, String name, Attributes attributes)63     public void startElement(String uri, String localName, String name, Attributes attributes)
64             throws SAXException {
65         super.startElement(uri, localName, name, attributes);
66         if ("package".equalsIgnoreCase(localName)) {
67             mCurrentPackageName = getValue(attributes, "name");
68 
69             ApiPackage apiPackage = new ApiPackage(mCurrentPackageName);
70             mApiCoverage.addPackage(apiPackage);
71 
72         } else if ("class".equalsIgnoreCase(localName) ||
73                 "interface".equalsIgnoreCase(localName)) {
74             if (isEnum(attributes)) {
75                 mIgnoreCurrentClass = true;
76                 return;
77             }
78             mIgnoreCurrentClass = false;
79             mCurrentClassName = getValue(attributes, "name");
80             mDeprecated = isDeprecated(attributes);
81             String superClass = attributes.getValue("extends");
82             ApiClass apiClass = new ApiClass(
83                     mCurrentClassName, mDeprecated, is(attributes, "abstract"), superClass);
84             ApiPackage apiPackage = mApiCoverage.getPackage(mCurrentPackageName);
85             apiPackage.addClass(apiClass);
86         } else if ("implements".equalsIgnoreCase(localName)) {
87             mCurrentInterfaceName = attributes.getValue("name");
88         } else if ("constructor".equalsIgnoreCase(localName)) {
89             mDeprecated = isDeprecated(attributes);
90             mCurrentParameterTypes.clear();
91         }  else if ("method".equalsIgnoreCase(localName)) {
92             mDeprecated = isDeprecated(attributes);
93             mCurrentMethodName = getValue(attributes, "name");
94             mCurrentMethodReturnType = getValue(attributes, "return");
95             mCurrentMethodIsAbstract = is(attributes, "abstract");
96             mCurrentMethodVisibility = getValue(attributes, "visibility");
97             mCurrentMethodStaticMethod = is(attributes, "static");
98             mCurrentMethodFinalMethod = is(attributes, "final");
99             mCurrentParameterTypes.clear();
100         } else if ("parameter".equalsIgnoreCase(localName)) {
101             mCurrentParameterTypes.add(getValue(attributes, "type"));
102         }
103     }
104 
105     @Override
endElement(String uri, String localName, String name)106     public void endElement(String uri, String localName, String name) throws SAXException {
107         super.endElement(uri, localName, name);
108         if (mIgnoreCurrentClass) {
109             // do not add anything for enum
110             return;
111         }
112         if ("constructor".equalsIgnoreCase(localName)) {
113             ApiConstructor apiConstructor = new ApiConstructor(mCurrentClassName,
114                     mCurrentParameterTypes, mDeprecated);
115             ApiPackage apiPackage = mApiCoverage.getPackage(mCurrentPackageName);
116             ApiClass apiClass = apiPackage.getClass(mCurrentClassName);
117             apiClass.addConstructor(apiConstructor);
118         } else if ("implements".equalsIgnoreCase(localName)) {
119             ApiPackage apiPackage = mApiCoverage.getPackage(mCurrentPackageName);
120             ApiClass apiClass = apiPackage.getClass(mCurrentClassName);
121             apiClass.addInterface(mCurrentInterfaceName);
122         } else if ("method".equalsIgnoreCase(localName)) {
123             ApiMethod apiMethod = new ApiMethod(
124                     mCurrentMethodName,
125                     mCurrentParameterTypes,
126                     mCurrentMethodReturnType,
127                     mDeprecated,
128                     mCurrentMethodVisibility,
129                     mCurrentMethodStaticMethod,
130                     mCurrentMethodFinalMethod,
131                     mCurrentMethodIsAbstract);
132             ApiPackage apiPackage = mApiCoverage.getPackage(mCurrentPackageName);
133             ApiClass apiClass = apiPackage.getClass(mCurrentClassName);
134             apiClass.addMethod(apiMethod);
135         }
136     }
137 
getValue(Attributes attributes, String key)138     static String getValue(Attributes attributes, String key) {
139         // Strip away generics <...> and make inner classes always use a "." rather than "$".
140         return attributes.getValue(key)
141                 .replaceAll("<.+>", "")
142                 .replace("$", ".");
143     }
144 
isDeprecated(Attributes attributes)145     private boolean isDeprecated(Attributes attributes) {
146         return "deprecated".equals(attributes.getValue("deprecated"));
147     }
148 
is(Attributes attributes, String valueName)149     private static boolean is(Attributes attributes, String valueName) {
150         return "true".equals(attributes.getValue(valueName));
151     }
152 
isEnum(Attributes attributes)153     private boolean isEnum(Attributes attributes) {
154         return "java.lang.Enum".equals(attributes.getValue("extends"));
155     }
156 }