Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9dd4e469 authored by Max Loh's avatar Max Loh
Browse files

Refactor with interface pattern, and throw exception for unsupported formats

Revised methods allow marshalling/unmarshalling from a list of XML nodes, allowing DataCategory to be incorporated seamlessly.
Factory pattern makes it easier to maintain createFromHrElements.
go/asl-tc-aosp

Bug: 287487923
Test: TODO in future CLs
Change-Id: I9fff3c1e28df74ef934da6355632c91e0ec91e79
parent ea141d2f
Loading
Loading
Loading
Loading
+38 −20
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@@ -33,7 +34,7 @@ import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

public class AndroidSafetyLabel {
public class AndroidSafetyLabel implements AslMarshallable {

    public enum Format {
        NULL, HUMAN_READABLE, ON_DEVICE;
@@ -45,31 +46,55 @@ public class AndroidSafetyLabel {
        return mSafetyLabels;
    }

    private AndroidSafetyLabel(SafetyLabels safetyLabels) {
    public AndroidSafetyLabel(SafetyLabels safetyLabels) {
        this.mSafetyLabels = safetyLabels;
    }

    /** Reads a {@link AndroidSafetyLabel} from an {@link InputStream}. */
    // TODO(b/329902686): Support conversion in both directions, specified by format.
    // TODO(b/329902686): Support parsing from on-device.
    public static AndroidSafetyLabel readFromStream(InputStream in, Format format)
            throws IOException, ParserConfigurationException, SAXException {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        Document document = factory.newDocumentBuilder().parse(in);

        switch (format) {
            case HUMAN_READABLE:
                Element appMetadataBundles =
                        XmlUtils.getSingleElement(document, XmlUtils.HR_TAG_APP_METADATA_BUNDLES);

        return AndroidSafetyLabel.createFromHrElement(appMetadataBundles);
                return new AndroidSafetyLabelFactory()
                        .createFromHrElements(
                                XmlUtils.asElementList(
                                        document.getElementsByTagName(
                                                XmlUtils.HR_TAG_APP_METADATA_BUNDLES)));
            case ON_DEVICE:
                throw new IllegalArgumentException(
                        "Parsing from on-device format is not supported at this time.");
            default:
                throw new IllegalStateException("Unrecognized input format.");
        }
    }

    /** Write the content of the {@link AndroidSafetyLabel} to a {@link OutputStream}. */
    // TODO(b/329902686): Support conversion in both directions, specified by format.
    // TODO(b/329902686): Support outputting human-readable format.
    public void writeToStream(OutputStream out, Format format)
            throws IOException, ParserConfigurationException, TransformerException {
        var docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        var document = docBuilder.newDocument();
        document.appendChild(this.toOdDomElement(document));

        switch (format) {
            case HUMAN_READABLE:
                throw new IllegalArgumentException(
                        "Outputting human-readable format is not supported at this time.");
            case ON_DEVICE:
                for (var child : this.toOdDomElements(document)) {
                    document.appendChild(child);
                }
                break;
            default:
                throw new IllegalStateException("Unrecognized input format.");
        }

        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
@@ -81,19 +106,12 @@ public class AndroidSafetyLabel {
        transformer.transform(domSource, streamResult);
    }

    /** Creates an {@link AndroidSafetyLabel} from human-readable DOM element */
    public static AndroidSafetyLabel createFromHrElement(Element appMetadataBundlesEle) {
        Element safetyLabelsEle =
                XmlUtils.getSingleElement(appMetadataBundlesEle, XmlUtils.HR_TAG_SAFETY_LABELS);
        SafetyLabels safetyLabels = SafetyLabels.createFromHrElement(safetyLabelsEle);
        return new AndroidSafetyLabel(safetyLabels);
    }

    /** Creates an on-device DOM element from an {@link AndroidSafetyLabel} */
    public Element toOdDomElement(Document doc) {
    @Override
    public List<Element> toOdDomElements(Document doc) {
        Element aslEle = doc.createElement(XmlUtils.OD_TAG_BUNDLE);
        aslEle.appendChild(mSafetyLabels.toOdDomElement(doc));
        return aslEle;
        XmlUtils.appendChildren(aslEle, mSafetyLabels.toOdDomElements(doc));
        return List.of(aslEle);
    }

    public static void test() {
+36 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.asllib;

import org.w3c.dom.Element;

import java.util.List;

public class AndroidSafetyLabelFactory implements AslMarshallableFactory<AndroidSafetyLabel> {

    /** Creates an {@link AndroidSafetyLabel} from human-readable DOM element */
    @Override
    public AndroidSafetyLabel createFromHrElements(List<Element> appMetadataBundles) {
        Element appMetadataBundlesEle = XmlUtils.getSingleElement(appMetadataBundles);
        Element safetyLabelsEle =
                XmlUtils.getSingleChildElement(
                        appMetadataBundlesEle, XmlUtils.HR_TAG_SAFETY_LABELS);
        SafetyLabels safetyLabels =
                new SafetyLabelsFactory().createFromHrElements(List.of(safetyLabelsEle));
        return new AndroidSafetyLabel(safetyLabels);
    }
}
+28 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.asllib;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.util.List;

public interface AslMarshallable {

    /** Creates the on-device DOM element from the AslMarshallable Java Object. */
    List<Element> toOdDomElements(Document doc);
}
+27 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.asllib;

import org.w3c.dom.Element;

import java.util.List;

public interface AslMarshallableFactory<T extends AslMarshallable> {

    /** Creates an {@link AslMarshallableFactory} from human-readable DOM element */
    T createFromHrElements(List<Element> elements);
}
+20 −5
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package com.android.asllib;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import java.util.List;
import java.util.Map;

/**
@@ -23,21 +27,32 @@ import java.util.Map;
 * are defined in {@link DataCategoryConstants}, each category has a valid set of types {@link
 * DataType}, which are mapped in {@link DataTypeConstants}
 */
public class DataCategory {
public class DataCategory implements AslMarshallable {
    private final String mCategoryName;
    private final Map<String, DataType> mDataTypes;

    private DataCategory(Map<String, DataType> dataTypes) {
    public DataCategory(String categoryName, Map<String, DataType> dataTypes) {
        this.mCategoryName = categoryName;
        this.mDataTypes = dataTypes;
    }

    public String getCategoryName() {
        return mCategoryName;
    }

    /** Return the type {@link Map} of String type key to {@link DataType} */

    public Map<String, DataType> getDataTypes() {
        return mDataTypes;
    }

    /** Creates a {@link DataCategory} given map of {@param dataTypes}. */
    public static DataCategory create(Map<String, DataType> dataTypes) {
        return new DataCategory(dataTypes);
    /** Creates on-device DOM element(s) from the {@link DataCategory}. */
    @Override
    public List<Element> toOdDomElements(Document doc) {
        Element dataCategoryEle = XmlUtils.createPbundleEleWithName(doc, this.getCategoryName());
        for (DataType dataType : mDataTypes.values()) {
            XmlUtils.appendChildren(dataCategoryEle, dataType.toOdDomElements(doc));
        }
        return List.of(dataCategoryEle);
    }
}
Loading