All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.brightsparklabs.asanti.model.schema.Decoder Maven / Gradle / Ivy

There is a newer version: 4.7.0
Show newest version
/*
 * Maintained by brightSPARK Labs.
 * www.brightsparklabs.com
 *
 * Refer to LICENSE at repository root for license details.
 */

package com.brightsparklabs.asanti.model.schema;

import com.brightsparklabs.asanti.common.OperationResult;
import com.brightsparklabs.asanti.model.schema.type.AsnSchemaComponentType;
import com.brightsparklabs.asanti.model.schema.type.AsnSchemaType;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author brightSPARK Labs
 */
public class Decoder {
    // -------------------------------------------------------------------------
    // CONSTANTS
    // -------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // CLASS VARIABLES
    // -------------------------------------------------------------------------

    /** Class logger. */
    private static final Logger logger = LoggerFactory.getLogger(Decoder.class);

    /** Splitter for separating tag strings. */
    private static final Splitter tagSplitter = Splitter.on("/").omitEmptyStrings();

    /** Joiner for creating tag strings. */
    private static final Joiner tagJoiner = Joiner.on("/");

    // -------------------------------------------------------------------------
    // INSTANCE VARIABLES
    // -------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // CONSTRUCTION
    // -------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // PUBLIC METHODS
    // -------------------------------------------------------------------------

    /**
     * Returns the decoded tags for the supplied raw tags. E.g. {@code
     * getDecodedTag("/0[1]/0[0]/0[1]", "Document")} => {@code "/Document/header/published/date"}
     * Decoding needs to be done on a whole data file at once time, as the ordering of the data can
     * impact the (validity of the) decoding, as ASN.1 SEQUENCE objects are order dependent. The
     * iteration order of the returned data will preserve the iteration order of rawTags, ie the
     * iteration order of the decoded tags will be as read from the data file (which should, for the
     * most part, be as defined in the schema).
     *
     * @param rawTags Raw tags to decode.
     * @param topLevelTypeName The name of the top level type in this module from which to begin
     *     decoding the raw tag.
     * @param schema The schema to decode against.
     * @return The result of the decode attempt containing the decoded tags for each of the rawTags.
     */
    public static ImmutableSet> getDecodedTags(
            final Iterable rawTags, final String topLevelTypeName, final AsnSchema schema) {

        final Optional type = schema.getType(topLevelTypeName);
        if (type.isEmpty()) {
            throw new RuntimeException("type [" + topLevelTypeName + "] does not exist in schema");
        }
        return getDecodedTags(rawTags, type.get());
    }

    /**
     * Returns the decoded tags for the supplied raw tags using a new {@link DecodingSession}.
     *
     * @param rawTags Raw tags to decode.
     * @param rootType The name of the top level type in this module from which to begin decoding
     *     the raw tag.
     * @return The result of the decode attempt containing the decoded tags for each of the rawTags.
     */
    public static ImmutableSet> getDecodedTags(
            final Iterable rawTags, final AsnSchemaType rootType) {
        DecodingSession session = new DecodingSessionImpl();

        // use LinkedHashSet to preserve insertion order
        final Set> results = Sets.newLinkedHashSet();
        for (String rawTag : rawTags) {
            final OperationResult decodeResult =
                    getDecodedTag(rawTag, rootType, session);

            results.add(decodeResult);
        }

        return ImmutableSet.copyOf(results);
    }

    /**
     * Returns the decoded tag for the supplied raw tag.
     *
     * 

E.g. {@code getDecodedTag("/0[1]/0[0]/0[1]", "Document")} => {@code * "/Document/header/published/date"} * * @param rawTag Raw tag to decode. * @param type The top level type from which to begin decoding the raw tag. * @param session The session state that tracks the ordering and stateful part of decoding a * complete set of asn data.. * @return The result of the decode attempt containing the decoded tag. */ public static OperationResult getDecodedTag( String rawTag, AsnSchemaType type, DecodingSession session) { final ArrayList tags = Lists.newArrayList(tagSplitter.split(rawTag)); final DecodedTagsAndType decodedTagsAndType = decodeTags(tags.iterator(), type, session); final List decodedTags = decodedTagsAndType.decodedTags; // check if decode was successful boolean decodeSuccessful = true; if (tags.size() != decodedTags.size()) { // could not decode decodeSuccessful = false; // copy unknown tags into result for (int i = decodedTags.size(); i < tags.size(); i++) { final String unknownTag = tags.get(i); decodedTags.add(unknownTag); logger.debug("Unable to parse " + rawTag + " : " + unknownTag); } } // The raw tags create a new '/' for collection elements (eg .../foo/[0]) // and we would rather have .../foo[0] final String decodedTagPath = tagJoiner.join(decodedTags).replaceAll("/\\[", "\\["); logger.trace("getDecodedTag {} => {}", rawTag, decodedTagPath); final DecodedTag decodedTag = new DecodedTag(decodedTagPath, rawTag, decodedTagsAndType.type, decodeSuccessful); return decodeSuccessful ? OperationResult.createSuccessfulInstance(decodedTag) : OperationResult.createUnsuccessfulInstance( decodedTag, "The supplied raw tag does not map to a type in this schema"); } // ------------------------------------------------------------------------- // PRIVATE METHODS // ------------------------------------------------------------------------- private static DecodedTagsAndType decodeTags( Iterator rawTags, AsnSchemaType containingType, DecodingSession decodingSession) { /* TODO: ASN-143. does this functionality now belong here? * all the logic is about AsnSchemaType object - should it have a decodeTags function? */ final DecodedTagsAndType result = new DecodedTagsAndType(); AsnSchemaType type = containingType; // It is possible to decode "/", which means return the containingType result.type = type; while (rawTags.hasNext()) { // Get the tag that we are decoding final String tag = rawTags.next(); final String decodedTagPath = tagJoiner.join(result.decodedTags).replaceAll("/\\[", "\\["); // By definition the new tag is the child of its container. decodingSession.setContext(decodedTagPath); Optional child = type.getMatchingChild(tag, decodingSession); if (child.isEmpty()) { // no type to delve into break; } final String decodedTag = child.get().getName(); result.type = child.get().getType(); result.decodedTags.add(decodedTag); type = result.type; } return result; } // ------------------------------------------------------------------------- // INTERNAL CLASS: DecodedTagAndType // ------------------------------------------------------------------------- /** * Transfer object to support returning a tuple of "Decoded Tags" and "Type" * * @author brightSPARK Labs */ public static class DecodedTagsAndType { /** list of decoded tags */ private final List decodedTags = Lists.newArrayList(); /** the type of the final tag */ private AsnSchemaType type = null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy