at.ac.univie.isc.asio.metadata.AtosMetadataRepository.java Source code

Java tutorial

Introduction

Here is the source code for at.ac.univie.isc.asio.metadata.AtosMetadataRepository.java

Source

/*
 * #%L
 * asio server
 * %%
 * Copyright (C) 2013 - 2015 Research Group Scientific Computing, University of Vienna
 * %%
 * 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.
 * #L%
 */
package at.ac.univie.isc.asio.metadata;

import net.atos.AtosDataset;
import net.atos.AtosMessage;
import net.atos.AtosResourceMetadata;
import net.atos.AtosResourceMetadataList;
import org.apache.http.HttpStatus;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Func1;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;
import java.util.concurrent.Callable;

/**
 * Connect to the atos vph-metadata repository to perform CRUD on dataset metadata.
 */
public final class AtosMetadataRepository {
    private final WebTarget endpoint;

    public AtosMetadataRepository(final WebTarget atosService) {
        endpoint = atosService;
    }

    /**
     * Find metadata on the dataset with given {@code globalID}.
     *
     * @param globalIdentifier identifier of the target dataset
     * @return metadata on target dataset if present
     */
    public Observable<AtosDataset> findOne(final String globalIdentifier) {
        return checkedRequest(new Callable<AtosDataset>() {
            @Override
            public AtosDataset call() throws Exception {
                final Response response = endpoint.path("/metadata/{identifier}")
                        .resolveTemplate("identifier", globalIdentifier).request(MediaType.APPLICATION_XML_TYPE)
                        .get();
                switch (response.getStatus()) {
                case HttpStatus.SC_OK:
                    return response.readEntity(AtosResourceMetadata.class).getDataset();
                case HttpStatus.SC_INTERNAL_SERVER_ERROR:
                case HttpStatus.SC_NOT_FOUND:
                    return null;
                default:
                    throw new WebApplicationException("unexpected http response code", response.getStatus());
                }
            }
        });
    }

    /**
     * Find metadata on the datasets with given {@code localID}.
     *
     * @param localIdentifier identifier of dataset
     * @return metadata on target dataset if present
     */
    public Observable<AtosDataset> findByLocalId(final String localIdentifier) {
        return checkedRequest(new Callable<List<AtosResourceMetadata>>() {
            @Override
            public List<AtosResourceMetadata> call() throws Exception {
                final AtosResourceMetadataList resources = endpoint.path("/metadata/facets/Dataset/localID")
                        .queryParam("value", localIdentifier).request(MediaType.APPLICATION_XML_TYPE)
                        .get(AtosResourceMetadataList.class);
                return resources.getResourceMetadata();
            }
        }).flatMap(new Func1<List<AtosResourceMetadata>, Observable<AtosResourceMetadata>>() {
            @Override
            public Observable<AtosResourceMetadata> call(final List<AtosResourceMetadata> resourceList) {
                return Observable.from(resourceList);
            }
        }).map(new Func1<AtosResourceMetadata, AtosDataset>() {
            @Override
            public AtosDataset call(final AtosResourceMetadata resource) {
                return resource.getDataset();
            }
        }).filter(new Func1<AtosDataset, Boolean>() {
            @Override
            public Boolean call(final AtosDataset atosDataset) {
                return atosDataset != null;
            }
        });
    }

    /**
     * Create a new metadata resource or update an existing one, depending on the globalId value of
     * the given dataset. If the globalID is {@code null} a new resource is created, else the given
     * identifier is used to update an existing resource if possible.
     *
     * @param data new metadata
     * @return new state of metadata resource
     */
    public Observable<AtosDataset> save(final AtosDataset data) {
        final AtosResourceMetadata wrapper = new AtosResourceMetadata().withDataset(data);
        final String identifier = data.getGlobalID();
        final Observable<AtosMessage> execution = (identifier == null) ? performCreate(wrapper)
                : performUpdate(identifier, wrapper);
        return execution.map(new Func1<AtosMessage, String>() {
            @Override
            public String call(final AtosMessage message) {
                return message.getData().getGlobalId();
            }
        }).flatMap(new Func1<String, Observable<AtosDataset>>() {
            @Override
            public Observable<AtosDataset> call(final String s) {
                return findOne(s);
            }
        });
    }

    /**
     * Create dataset as a new resource with auto-generated id
     */
    private Observable<AtosMessage> performCreate(final AtosResourceMetadata data) {
        return checkedRequest(new Callable<AtosMessage>() {
            @Override
            public AtosMessage call() throws Exception {
                return endpoint.path("/metadata").request(MediaType.APPLICATION_XML_TYPE)
                        .post(Entity.entity(data, MediaType.APPLICATION_XML_TYPE), AtosMessage.class);
            }
        });
    }

    /**
     * Update an existing metadata resource
     */
    private Observable<AtosMessage> performUpdate(final String identifier, final AtosResourceMetadata data) {
        return checkedRequest(new Callable<AtosMessage>() {
            @Override
            public AtosMessage call() throws Exception {
                return endpoint.path("/metadata/{identifier}").resolveTemplate("identifier", identifier)
                        .request(MediaType.APPLICATION_XML_TYPE)
                        .put(Entity.entity(data, MediaType.APPLICATION_XML_TYPE), AtosMessage.class);
            }
        });
    }

    /**
     * Delete the metadata resource with given {@code globalID}.
     *
     * @param globalIdentifier id of the target resource
     * @return the identifier of the deleted resource
     */
    public Observable<String> delete(final String globalIdentifier) {
        return checkedRequest(new Callable<String>() {
            @Override
            public String call() throws Exception {
                endpoint.path("/metadata/{identifier}").resolveTemplate("identifier", globalIdentifier)
                        .request(MediaType.APPLICATION_XML_TYPE).delete(AtosMessage.class);
                return globalIdentifier;
            }
        });
    }

    /**
     * perform given interaction with repository and handle errors
     */
    private <TYPE> Observable<TYPE> checkedRequest(final Callable<TYPE> action) {
        return Observable.create(new ReactiveCallable<>(action));
    }

    /**
     * Turn the given {@code Callable} into an {@code Observable}, that may yield zero or a single
     * item.
     *
     * @param <TYPE> type of the single result
     */
    private class ReactiveCallable<TYPE> implements Observable.OnSubscribe<TYPE> {
        private final Callable<TYPE> action;

        public ReactiveCallable(final Callable<TYPE> action) {
            this.action = action;
        }

        @Override
        public void call(final Subscriber<? super TYPE> subscriber) {
            try {
                final TYPE result = action.call();
                if (result != null) {
                    subscriber.onNext(result);
                }
                subscriber.onCompleted();
            } catch (Exception error) {
                subscriber.onError(wrapError(error));
            }
        }
    }

    private RuntimeException wrapError(final Exception original) {
        if (original instanceof RepositoryFailure) {
            return (RuntimeException) original;
        }
        return new RepositoryFailure(original.getMessage(), endpoint.getUri(), original);
    }

    @Override
    public String toString() {
        return "AtosMetadataRepository{" + "endpoint=" + endpoint.getUri() + '}';
    }
}