org.sfs.nodes.compute.container.GetContainer.java Source code

Java tutorial

Introduction

Here is the source code for org.sfs.nodes.compute.container.GetContainer.java

Source

/*
 * Copyright 2016 The Simple File Server Authors
 *
 * 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 org.sfs.nodes.compute.container;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.common.net.MediaType;
import io.vertx.core.Handler;
import io.vertx.core.MultiMap;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.logging.Logger;
import org.sfs.Server;
import org.sfs.SfsRequest;
import org.sfs.VertxContext;
import org.sfs.auth.Authenticate;
import org.sfs.elasticsearch.container.ListObjects;
import org.sfs.elasticsearch.container.LoadAccountAndContainer;
import org.sfs.elasticsearch.container.LoadContainerStats;
import org.sfs.io.AsyncIO;
import org.sfs.io.BufferOutputStream;
import org.sfs.metadata.Metadata;
import org.sfs.rx.ConnectionCloseTerminus;
import org.sfs.rx.Defer;
import org.sfs.util.SfsHttpQueryParams;
import org.sfs.validate.ValidateActionAuthenticated;
import org.sfs.validate.ValidateActionContainerListObjects;
import org.sfs.validate.ValidateContainerPath;
import org.sfs.vo.ContainerStats;
import org.sfs.vo.ObjectList;
import rx.Observable;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.SortedSet;

import static com.fasterxml.jackson.core.JsonEncoding.UTF8;
import static com.google.common.base.Charsets.UTF_8;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.Ordering.from;
import static com.google.common.io.BaseEncoding.base16;
import static com.google.common.net.HttpHeaders.ACCEPT;
import static com.google.common.net.MediaType.APPLICATION_XML_UTF_8;
import static com.google.common.net.MediaType.JSON_UTF_8;
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
import static com.google.common.net.MediaType.parse;
import static io.vertx.core.logging.LoggerFactory.getLogger;
import static java.lang.String.format;
import static java.lang.String.valueOf;
import static java.math.BigDecimal.ROUND_HALF_UP;
import static javax.xml.stream.XMLOutputFactory.newFactory;
import static org.sfs.elasticsearch.container.ListObjects.ListedObject;
import static org.sfs.rx.Defer.aVoid;
import static org.sfs.rx.Defer.just;
import static org.sfs.rx.RxHelper.combineSinglesDelayError;
import static org.sfs.util.DateFormatter.toDateTimeString;
import static org.sfs.util.NullSafeAscii.equalsIgnoreCase;
import static org.sfs.util.SfsHttpHeaders.X_ADD_CONTAINER_META_PREFIX;
import static org.sfs.util.SfsHttpHeaders.X_CONTAINER_BYTES_USED;
import static org.sfs.util.SfsHttpHeaders.X_CONTAINER_OBJECT_COUNT;
import static org.sfs.util.SfsHttpQueryParams.FORMAT;
import static org.sfs.vo.ObjectPath.fromPaths;
import static org.sfs.vo.ObjectPath.fromSfsRequest;

public class GetContainer implements Handler<SfsRequest> {

    private static final Logger LOGGER = getLogger(GetContainer.class);

    @Override
    public void handle(final SfsRequest httpServerRequest) {

        VertxContext<Server> vertxContext = httpServerRequest.vertxContext();
        aVoid().flatMap(new Authenticate(httpServerRequest))
                .flatMap(new ValidateActionAuthenticated(httpServerRequest))
                .map(aVoid -> fromSfsRequest(httpServerRequest)).map(new ValidateContainerPath())
                .flatMap(new LoadAccountAndContainer(vertxContext))
                .flatMap(new ValidateActionContainerListObjects(httpServerRequest)).flatMap(persistentContainer -> {

                    HttpServerResponse httpServerResponse = httpServerRequest.response();

                    MultiMap queryParams = httpServerRequest.params();
                    MultiMap headerParams = httpServerRequest.headers();

                    String format = queryParams.get(FORMAT);
                    String accept = headerParams.get(ACCEPT);

                    MediaType parsedAccept = null;

                    if (equalsIgnoreCase("xml", format)) {
                        parsedAccept = APPLICATION_XML_UTF_8;
                    } else if (equalsIgnoreCase("json", format)) {
                        parsedAccept = JSON_UTF_8;
                    }

                    if (parsedAccept == null) {
                        if (!isNullOrEmpty(accept)) {
                            parsedAccept = parse(accept);
                        }
                    }

                    if (parsedAccept == null || (!PLAIN_TEXT_UTF_8.is(parsedAccept)
                            && !APPLICATION_XML_UTF_8.is(parsedAccept) && !JSON_UTF_8.equals(parsedAccept))) {
                        parsedAccept = PLAIN_TEXT_UTF_8;
                    }

                    Observable<Optional<ContainerStats>> oContainerStats;
                    boolean hasPrefix = !Strings.isNullOrEmpty(queryParams.get(SfsHttpQueryParams.PREFIX));
                    if (hasPrefix) {
                        oContainerStats = just(persistentContainer)
                                .flatMap(new LoadContainerStats(httpServerRequest.vertxContext()))
                                .map(Optional::of);
                    } else {
                        oContainerStats = Defer.just(Optional.<ContainerStats>absent());
                    }

                    Observable<ObjectList> oObjectListing = just(persistentContainer)
                            .flatMap(new ListObjects(httpServerRequest));

                    MediaType finalParsedAccept = parsedAccept;
                    return combineSinglesDelayError(oContainerStats, oObjectListing,
                            (containerStats, objectList) -> {

                                if (containerStats.isPresent()) {

                                    Metadata metadata = persistentContainer.getMetadata();

                                    for (String key : metadata.keySet()) {
                                        SortedSet<String> values = metadata.get(key);
                                        if (values != null && !values.isEmpty()) {
                                            httpServerResponse.putHeader(
                                                    format("%s%s", X_ADD_CONTAINER_META_PREFIX, key), values);
                                        }
                                    }

                                    httpServerResponse.putHeader(X_CONTAINER_OBJECT_COUNT,
                                            valueOf(containerStats.get().getObjectCount()));
                                    httpServerResponse.putHeader(X_CONTAINER_BYTES_USED,
                                            BigDecimal.valueOf(containerStats.get().getBytesUsed())
                                                    .setScale(0, ROUND_HALF_UP).toString());
                                }

                                BufferOutputStream bufferOutputStream = new BufferOutputStream();

                                if (JSON_UTF_8.is(finalParsedAccept)) {

                                    try {
                                        JsonFactory jsonFactory = vertxContext.verticle().jsonFactory();
                                        JsonGenerator jg = jsonFactory.createGenerator(bufferOutputStream, UTF8);
                                        jg.writeStartArray();

                                        for (ListedObject listedObject : ordered(objectList.getObjects())) {

                                            jg.writeStartObject();
                                            jg.writeStringField("hash",
                                                    base16().lowerCase().encode(listedObject.getEtag()));
                                            jg.writeStringField("last_modified",
                                                    toDateTimeString(listedObject.getLastModified()));
                                            jg.writeNumberField("bytes", listedObject.getLength());
                                            jg.writeStringField("content_type", listedObject.getContentType());
                                            jg.writeStringField("name", listedObject.getName());
                                            jg.writeEndObject();
                                        }

                                        jg.writeEndArray();
                                        jg.close();
                                    } catch (IOException e) {
                                        throw new RuntimeException(e);
                                    }

                                } else if (APPLICATION_XML_UTF_8.is(finalParsedAccept)) {

                                    String charset = UTF_8.toString();
                                    XMLStreamWriter writer = null;
                                    try {
                                        writer = newFactory().createXMLStreamWriter(bufferOutputStream, charset);

                                        writer.writeStartDocument(charset, "1.0");

                                        writer.writeStartElement("container");

                                        writer.writeAttribute("name",
                                                fromPaths(persistentContainer.getId()).containerName().get());

                                        for (ListedObject listedObject : ordered(objectList.getObjects())) {

                                            writer.writeStartElement("object");

                                            writer.writeStartElement("name");
                                            writer.writeCharacters(listedObject.getName());
                                            writer.writeEndElement();

                                            writer.writeStartElement("hash");
                                            writer.writeCharacters(
                                                    base16().lowerCase().encode(listedObject.getEtag()));
                                            writer.writeEndElement();

                                            writer.writeStartElement("bytes");
                                            writer.writeCharacters(valueOf(listedObject.getLength()));
                                            writer.writeEndElement();

                                            writer.writeStartElement("content_type");
                                            writer.writeCharacters(listedObject.getContentType());
                                            writer.writeEndElement();

                                            writer.writeStartElement("last_modified");
                                            writer.writeCharacters(
                                                    toDateTimeString(listedObject.getLastModified()));
                                            writer.writeEndElement();

                                            writer.writeEndElement();
                                        }

                                        writer.writeEndElement();

                                        writer.writeEndDocument();

                                    } catch (XMLStreamException e) {
                                        throw new RuntimeException(e);
                                    } finally {
                                        try {
                                            if (writer != null) {
                                                writer.close();
                                            }
                                        } catch (XMLStreamException e) {
                                            LOGGER.warn(e.getLocalizedMessage(), e);
                                        }
                                    }

                                } else {
                                    String charset = UTF_8.toString();
                                    try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
                                            bufferOutputStream, charset)) {
                                        for (ListedObject listedObject : ordered(objectList.getObjects())) {
                                            outputStreamWriter.write(listedObject.getName());
                                            outputStreamWriter.write("\n");
                                        }
                                    } catch (IOException e) {
                                        throw new RuntimeException(e);
                                    }
                                }
                                objectList.clear();
                                return bufferOutputStream;
                            }).flatMap(bufferOutputStream -> {
                                Buffer buffer = bufferOutputStream.toBuffer();
                                httpServerResponse.putHeader(HttpHeaders.CONTENT_TYPE, finalParsedAccept.toString())
                                        .putHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(buffer.length()));
                                return AsyncIO.append(buffer, httpServerRequest.response());
                            });
                }).single().subscribe(new ConnectionCloseTerminus<Void>(httpServerRequest) {
                    @Override
                    public void onNext(Void aVoid) {

                    }
                }

        );

    }

    protected Iterable<ListedObject> ordered(Iterable<ListedObject> iterable) {
        return from(new Comparator<ListedObject>() {
            @Override
            public int compare(ListedObject o1, ListedObject o2) {
                return o1.getName().compareTo(o2.getName());
            }
        }).sortedCopy(iterable);
    }
}