org.eclipse.packagedrone.repo.channel.apm.ChannelReader.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.packagedrone.repo.channel.apm.ChannelReader.java

Source

/*******************************************************************************
 * Copyright (c) 2015, 2016 IBH SYSTEMS GmbH.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBH SYSTEMS GmbH - initial API and implementation
 *******************************************************************************/
package org.eclipse.packagedrone.repo.channel.apm;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.packagedrone.repo.MetaKey;
import org.eclipse.packagedrone.repo.Severity;
import org.eclipse.packagedrone.repo.channel.ArtifactInformation;
import org.eclipse.packagedrone.repo.channel.CacheEntryInformation;
import org.eclipse.packagedrone.repo.channel.ChannelState;
import org.eclipse.packagedrone.repo.channel.ValidationMessage;
import org.eclipse.packagedrone.repo.channel.apm.store.BlobStore;
import org.eclipse.packagedrone.repo.channel.apm.store.CacheStore;

import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;

public class ChannelReader implements AutoCloseable {
    private final InputStream stream;

    private final String channelId;

    private final BlobStore store;

    private final CacheStore cacheStore;

    private final DateFormat dateFormat;

    private long numberOfBytes;

    public ChannelReader(final InputStream stream, final String channelId, final BlobStore store,
            final CacheStore cacheStore) {
        this.stream = stream;
        this.channelId = channelId;
        this.store = store;
        this.cacheStore = cacheStore;

        this.dateFormat = new SimpleDateFormat(ChannelModelProvider.DATE_FORMAT);
    }

    public ModifyContextImpl read() throws IOException {
        this.numberOfBytes = 0;

        final Reader reader = new InputStreamReader(this.stream, StandardCharsets.UTF_8);

        final ChannelState.Builder state = new ChannelState.Builder();

        Boolean locked = null;

        Map<MetaKey, CacheEntryInformation> cacheEntries = Collections.emptyMap();
        Map<String, ArtifactInformation> artifacts = Collections.emptyMap();
        Map<MetaKey, String> extractedMetaData = Collections.emptyMap();
        Map<MetaKey, String> providedMetaData = Collections.emptyMap();
        Map<String, String> aspects = new HashMap<>();

        final JsonReader jr = new JsonReader(reader);

        jr.beginObject();
        while (jr.hasNext()) {
            final String name = jr.nextName();
            switch (name) {
            case "locked":
                state.setLocked(locked = jr.nextBoolean());
                break;
            case "creationTimestamp":
                state.setCreationTimestamp(readTime(jr));
                break;
            case "modificationTimestamp":
                state.setModificationTimestamp(readTime(jr));
                break;
            case "cacheEntries":
                cacheEntries = readCacheEntries(jr);
                break;
            case "artifacts":
                artifacts = readArtifacts(jr);
                break;
            case "extractedMetaData":
                extractedMetaData = readMetadata(jr);
                break;
            case "providedMetaData":
                providedMetaData = readMetadata(jr);
                break;
            case "validationMessages":
                state.setValidationMessages(readValidationMessages(jr));
                break;
            case "aspects":
                aspects = readAspects(jr);
                break;
            default:
                jr.skipValue();
                break;
            }
        }
        jr.endObject();

        if (locked == null) {
            throw new IOException("Missing values for channel");
        }

        // transient information

        state.setNumberOfArtifacts(artifacts.size());
        state.setNumberOfBytes(this.numberOfBytes);

        // create result

        return new ModifyContextImpl(this.channelId, this.store, this.cacheStore, state.build(), aspects, artifacts,
                cacheEntries, extractedMetaData, providedMetaData);
    }

    private Map<String, String> readAspects(final JsonReader jr) throws IOException {
        final Map<String, String> result = new HashMap<>();

        jr.beginObject();
        while (jr.hasNext()) {
            switch (jr.nextName()) {
            case "map":
                jr.beginObject();
                while (jr.hasNext()) {
                    final String id = jr.nextName();
                    String value = null;
                    if (jr.peek() == JsonToken.STRING) {
                        value = jr.nextString();
                    } else {
                        jr.skipValue();
                    }
                    result.put(id, value);
                }
                jr.endObject();
                break;
            }
        }
        jr.endObject();

        return result;
    }

    private Map<String, ArtifactInformation> readArtifacts(final JsonReader jr) throws IOException {
        jr.beginObject();

        final Map<String, ArtifactInformation> result = new HashMap<>();

        while (jr.hasNext()) {
            final String id = jr.nextName();
            jr.beginObject();

            String name = null;
            Long size = null;
            Instant creationTimestamp = null;
            String parentId = null;
            Set<String> childIds = Collections.emptySet();
            Set<String> facets = Collections.emptySet();
            String virtualizerAspectId = null;
            List<ValidationMessage> validationMessages = Collections.emptyList();
            Map<MetaKey, String> extractedMetaData = Collections.emptyMap();
            Map<MetaKey, String> providedMetaData = Collections.emptyMap();

            while (jr.hasNext()) {
                final String ele = jr.nextName();
                switch (ele) {
                case "name":
                    name = jr.nextString();
                    break;
                case "size":
                    size = jr.nextLong();
                    break;
                case "date":
                    creationTimestamp = readTime(jr);
                    break;
                case "parentId":
                    parentId = jr.nextString();
                    break;
                case "childIds":
                    childIds = readSet(jr);
                    break;
                case "facets":
                    facets = readSet(jr);
                    break;
                case "virtualizerAspectId":
                    virtualizerAspectId = jr.nextString();
                    break;
                case "extractedMetaData":
                    extractedMetaData = readMetadata(jr);
                    break;
                case "providedMetaData":
                    providedMetaData = readMetadata(jr);
                    break;
                case "validationMessages":
                    validationMessages = readValidationMessages(jr);
                    break;
                default:
                    jr.skipValue();
                    break;
                }
            }
            jr.endObject();

            if (id == null || name == null || size == null || creationTimestamp == null) {
                throw new IOException("Missing values for artifact");
            }

            this.numberOfBytes += size;

            result.put(id, new ArtifactInformation(id, parentId, childIds, name, size, creationTimestamp, facets,
                    validationMessages, providedMetaData, extractedMetaData, virtualizerAspectId));
        }

        jr.endObject();

        return result;
    }

    private Map<MetaKey, String> readMetadata(final JsonReader jr) throws IOException {
        final Map<MetaKey, String> result = new HashMap<>();

        jr.beginObject();

        while (jr.hasNext()) {
            final String name = jr.nextName();
            if (jr.peek() == JsonToken.NULL) {
                jr.skipValue();
            } else {
                final String value = jr.nextString();
                result.put(MetaKey.fromString(name), value);
            }
        }

        jr.endObject();

        return result;
    }

    private List<ValidationMessage> readValidationMessages(final JsonReader jr) throws IOException {
        final List<ValidationMessage> result = new LinkedList<>();

        jr.beginArray();
        while (jr.hasNext()) {
            result.add(readValidationMessage(jr));
        }
        jr.endArray();

        return result;
    }

    private ValidationMessage readValidationMessage(final JsonReader jr) throws IOException {
        String aspectId = null;
        Severity severity = null;
        String message = null;
        Set<String> artifactIds = Collections.emptySet();

        jr.beginObject();
        while (jr.hasNext()) {
            final String name = jr.nextName();
            switch (name) {
            case "aspectId":
                aspectId = jr.nextString();
                break;
            case "severity":
                severity = Severity.valueOf(jr.nextString());
                break;
            case "message":
                message = jr.nextString();
                break;
            case "artifactIds":
                artifactIds = readSet(jr);
                break;
            }
        }
        jr.endObject();

        if (aspectId == null || severity == null || message == null) {
            throw new IOException("Missing values in validation message");
        }

        return new ValidationMessage(aspectId, severity, message, artifactIds);
    }

    private Set<String> readSet(final JsonReader jr) throws IOException {
        final Set<String> result = new HashSet<>();

        jr.beginArray();
        while (jr.hasNext()) {
            result.add(jr.nextString());
        }
        jr.endArray();

        return result;
    }

    private Map<MetaKey, CacheEntryInformation> readCacheEntries(final JsonReader jr) throws IOException {
        final Map<MetaKey, CacheEntryInformation> result = new HashMap<>();

        jr.beginObject();
        while (jr.hasNext()) {
            final String entryName = jr.nextName();
            jr.beginObject();

            String name = null;
            Long size = null;
            String mimeType = null;
            Instant timestamp = null;

            while (jr.hasNext()) {
                final String ele = jr.nextName();
                switch (ele) {
                case "name":
                    name = jr.nextString();
                    break;
                case "size":
                    size = jr.nextLong();
                    break;
                case "mimeType":
                    mimeType = jr.nextString();
                    break;
                case "timestamp":
                    timestamp = readTime(jr);
                    break;
                default:
                    jr.skipValue();
                    break;
                }
            }

            if (name == null || size == null || mimeType == null || timestamp == null) {
                throw new IOException("Invalid format");
            }

            jr.endObject();

            final MetaKey key = MetaKey.fromString(entryName);

            result.put(key, new CacheEntryInformation(key, name, size, mimeType, timestamp));
        }
        jr.endObject();

        return result;
    }

    private Instant readTime(final JsonReader jr) throws IOException {
        final JsonToken peek = jr.peek();
        if (peek == JsonToken.NUMBER) {
            return Instant.ofEpochMilli(jr.nextLong());
        } else if (peek == JsonToken.NULL) {
            jr.nextNull();
            return null;
        } else if (peek == JsonToken.STRING) {
            final String str = jr.nextString();

            try {
                return Instant.ofEpochMilli(Long.parseLong(str));
            } catch (final NumberFormatException e) {
                try {
                    return this.dateFormat.parse(str).toInstant();
                } catch (final ParseException e2) {
                    throw new IOException(e2);
                }
            }
        } else {
            throw new IOException(String.format("Invalid timestamp token: %s", peek));
        }
    }

    @Override
    public void close() throws IOException {
        this.stream.close();
    }
}