1 /*
2  * Copyright (C) 2016 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 package com.android.compatibility.common.tradefed.testtype;
17 
18 import com.android.compatibility.common.util.TestFilter;
19 import com.android.tradefed.util.xml.AbstractXmlParser;
20 
21 import org.kxml2.io.KXmlSerializer;
22 import org.xml.sax.Attributes;
23 import org.xml.sax.SAXException;
24 import org.xml.sax.helpers.DefaultHandler;
25 
26 import java.io.IOException;
27 import java.io.OutputStream;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.HashSet;
31 import java.util.Set;
32 
33 /**
34  * Container, parser, and generator of SubPlan info.
35  */
36 public class SubPlan extends AbstractXmlParser implements ISubPlan {
37 
38     private final Set<String> mIncludes;
39     private final Set<String> mExcludes;
40 
41     private static final String ENCODING = "UTF-8";
42     private static final String NS = null; // namespace used for XML serializer
43     private static final String VERSION_ATTR = "version";
44     private static final String SUBPLAN_VERSION = "2.0";
45 
46     private static final String SUBPLAN_TAG = "SubPlan";
47     private static final String ENTRY_TAG = "Entry";
48     private static final String EXCLUDE_ATTR = "exclude";
49     private static final String INCLUDE_ATTR = "include";
50     private static final String ABI_ATTR = "abi";
51     private static final String NAME_ATTR = "name";
52 
SubPlan()53     public SubPlan() {
54         mIncludes = new HashSet<String>();
55         mExcludes = new HashSet<String>();
56     }
57 
58     /**
59      * {@inheritDoc}
60      */
61     @Override
addIncludeFilter(String filter)62     public void addIncludeFilter(String filter) {
63         mIncludes.add(filter);
64     }
65 
66     /**
67      * {@inheritDoc}
68      */
69     @Override
addAllIncludeFilters(Set<String> filters)70     public void addAllIncludeFilters(Set<String> filters) {
71         mIncludes.addAll(filters);
72     }
73 
74     /**
75      * {@inheritDoc}
76      */
77     @Override
addExcludeFilter(String filter)78     public void addExcludeFilter(String filter) {
79         mExcludes.add(filter);
80     }
81 
82     /**
83      * {@inheritDoc}
84      */
85     @Override
addAllExcludeFilters(Set<String> filters)86     public void addAllExcludeFilters(Set<String> filters) {
87         mExcludes.addAll(filters);
88     }
89 
90     /**
91      * {@inheritDoc}
92      */
93     @Override
getIncludeFilters()94     public Set<String> getIncludeFilters() {
95         return new HashSet<String>(mIncludes);
96     }
97 
98     /**
99      * {@inheritDoc}
100      */
101     @Override
getExcludeFilters()102     public Set<String> getExcludeFilters() {
103         return new HashSet<String>(mExcludes);
104     }
105 
106     /**
107      * {@inheritDoc}
108      */
109     @Override
clearExcludeFilters()110     public void clearExcludeFilters() {
111         mExcludes.clear();
112     }
113 
114     /**
115      * {@inheritDoc}
116      */
117     @Override
clearIncludeFilters()118     public void clearIncludeFilters() {
119         mIncludes.clear();
120     }
121 
122     /**
123      * {@inheritDoc}
124      */
125     @Override
serialize(OutputStream stream)126     public void serialize(OutputStream stream) throws IOException {
127         KXmlSerializer serializer = new KXmlSerializer();
128         serializer.setOutput(stream, ENCODING);
129         serializer.startDocument(ENCODING, false);
130         serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
131         serializer.startTag(NS, SUBPLAN_TAG);
132         serializer.attribute(NS, VERSION_ATTR, SUBPLAN_VERSION);
133 
134         ArrayList<String> sortedIncludes = new ArrayList<String>(mIncludes);
135         ArrayList<String> sortedExcludes = new ArrayList<String>(mExcludes);
136         Collections.sort(sortedIncludes);
137         Collections.sort(sortedExcludes);
138         for (String include : sortedIncludes) {
139             serializer.startTag(NS, ENTRY_TAG);
140             serializer.attribute(NS, INCLUDE_ATTR, include);
141             serializer.endTag(NS, ENTRY_TAG);
142         }
143         for (String exclude : sortedExcludes) {
144             serializer.startTag(NS, ENTRY_TAG);
145             serializer.attribute(NS, EXCLUDE_ATTR, exclude);
146             serializer.endTag(NS, ENTRY_TAG);
147         }
148 
149         serializer.endTag(NS, SUBPLAN_TAG);
150         serializer.endDocument();
151     }
152 
153     /**
154      * {@inheritDoc}
155      */
156     @Override
createXmlHandler()157     protected DefaultHandler createXmlHandler() {
158         return new EntryHandler();
159     }
160 
161     /**
162      * SAX callback object. Handles parsing data from the xml tags.
163      */
164     private class EntryHandler extends DefaultHandler {
165 
166         @Override
startElement(String uri, String localName, String name, Attributes attributes)167         public void startElement(String uri, String localName, String name, Attributes attributes)
168                 throws SAXException {
169             if (ENTRY_TAG.equals(localName)) {
170                 String includeString = attributes.getValue(INCLUDE_ATTR);
171                 String excludeString = attributes.getValue(EXCLUDE_ATTR);
172                 if (includeString != null && excludeString != null) {
173                     throw new IllegalArgumentException(
174                             "Cannot specify include and exclude filter in the same element");
175                 }
176                 String abiString = attributes.getValue(ABI_ATTR);
177                 String nameString = attributes.getValue(NAME_ATTR);
178 
179                 if (excludeString == null) {
180                     parseFilter(abiString, nameString, includeString, mIncludes);
181                 } else {
182                     parseFilter(abiString, nameString, excludeString, mExcludes);
183                 }
184             }
185         }
186 
parseFilter(String abi, String name, String filter, Set<String> filterSet)187         private void parseFilter(String abi, String name, String filter, Set<String> filterSet) {
188             if (name == null) {
189                 // ignore name and abi attributes, 'filter' should contain all necessary parts
190                 filterSet.add(filter);
191             } else {
192                 // 'filter' is name of test. Build TestFilter and convert back to string
193                 filterSet.add(new TestFilter(abi, name, filter).toString());
194             }
195         }
196     }
197 }
198