org.obiba.opal.rest.client.magma.RestDatasource.java Source code

Java tutorial

Introduction

Here is the source code for org.obiba.opal.rest.client.magma.RestDatasource.java

Source

/*
 * Copyright (c) 2013 OBiBa. All rights reserved.
 *
 * This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.obiba.opal.rest.client.magma;

import java.io.IOException;
import java.net.ConnectException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Set;

import javax.validation.constraints.NotNull;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.util.EntityUtils;
import org.obiba.magma.MagmaRuntimeException;
import org.obiba.magma.Timestamps;
import org.obiba.magma.TimestampsBean;
import org.obiba.magma.Value;
import org.obiba.magma.ValueTable;
import org.obiba.magma.ValueTableWriter;
import org.obiba.magma.support.AbstractDatasource;
import org.obiba.magma.support.Initialisables;
import org.obiba.magma.type.DateTimeType;
import org.obiba.opal.web.model.Magma.DatasourceDto;
import org.obiba.opal.web.model.Magma.TableDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;

public class RestDatasource extends AbstractDatasource {

    private static final Logger log = LoggerFactory.getLogger(RestDatasource.class);

    private final OpalJavaClient opalClient;

    private final URI datasourceURI;

    private Timestamps timestamps;

    public RestDatasource(String name, String opalUri, String remoteDatasource, String username, String password)
            throws URISyntaxException {
        this(name, new OpalJavaClient(opalUri, username, password), remoteDatasource);
    }

    public RestDatasource(String name, OpalJavaClient opalClient, String remoteDatasource) {
        super(name, "rest");
        this.opalClient = opalClient;
        datasourceURI = opalClient.newUri().segment("datasource", remoteDatasource).build();
    }

    @NotNull
    @Override
    public Timestamps getTimestamps() {
        if (timestamps == null) {
            refresh();
        }

        return timestamps;
    }

    @Override
    public Set<ValueTable> getValueTables() {
        refresh();

        return super.getValueTables();
    }

    @Override
    public void initialise() {
        try {
            super.initialise();
        } catch (RuntimeException e) {
            if (e.getCause() instanceof ConnectException) {
                log.error("Failed connecting to Opal server: {}", e.getMessage(), e);
            } else {
                log.error("Unexpected error while communicating with Opal server: {}", e.getMessage(), e);
            }
            throw new MagmaRuntimeException(e.getMessage(), e);
        }
    }

    @Override
    protected void onDispose() {
        super.onDispose();
        try {
            opalClient.close();
        } catch (Exception ignore) {
            // ignore
        }
    }

    @Override
    protected Set<String> getValueTableNames() {
        DatasourceDto d = opalClient.getResource(DatasourceDto.class, datasourceURI, DatasourceDto.newBuilder());
        return ImmutableSet.copyOf(d.getTableList());
    }

    @NotNull
    @Override
    public ValueTableWriter createWriter(@NotNull String tableName, @NotNull String entityType) {
        if (!hasValueTable(tableName)) {
            URI tableUri = newReference("tables");
            try {
                HttpResponse response = getOpalClient().post(tableUri,
                        TableDto.newBuilder().setName(tableName).setEntityType(entityType).build());
                if (response.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED) {
                    throw new RuntimeException("cannot create table " + response.getStatusLine().getReasonPhrase());
                }
                addValueTable(tableName);
                EntityUtils.consume(response.getEntity());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return new RestValueTableWriter((RestValueTable) getValueTable(tableName));
    }

    @Override
    protected ValueTable initialiseValueTable(String tableName) {
        return new RestValueTable(this, opalClient.getResource(TableDto.class,
                newUri("table", tableName).query("counts", "false").build(), TableDto.newBuilder()));
    }

    private synchronized void refresh() {
        try {
            DatasourceDto d = opalClient.getResource(DatasourceDto.class, datasourceURI,
                    DatasourceDto.newBuilder());
            Value currentTimestamp = DateTimeType.get().valueOf(d.getTimestamps().getLastUpdate());

            if (timestamps != null && timestamps.getLastUpdate().equals(currentTimestamp)) {
                log.debug("RestDatasource is up to date. Skipping refresh.");
                return; //Cache is up to date
            }

            log.debug("Refreshing data source value tables.");

            Set<String> cachedTableNames = ImmutableSet
                    .copyOf(Iterables.transform(super.getValueTables(), new Function<ValueTable, String>() {
                        @Override
                        public String apply(ValueTable input) {
                            return input.getName();
                        }
                    }));

            timestamps = new TimestampsBean(DateTimeType.get().valueOf(d.getTimestamps().getCreated()),
                    DateTimeType.get().valueOf(d.getTimestamps().getLastUpdate()));
            Set<String> currentTables = ImmutableSet.copyOf(d.getTableList());

            for (String tableName : cachedTableNames) {
                ValueTable table = getCachedValueTable(tableName);
                removeValueTable(table);
            }

            for (String tableName : currentTables) {
                addValueTable(tableName);
            }
        } catch (Exception e) {
            log.error("Failed refreshing value tables from Opal server: {}", e.getMessage(), e);

            if (e.getCause() instanceof ConnectException) {
                log.error("Failed connecting to Opal server: {}", e.getMessage(), e);
            } else {
                log.error("Unexpected error while communicating with Opal server: {}", e.getMessage(), e);
            }

            throw new MagmaRuntimeException(e.getMessage(), e);
        }
    }

    private ValueTable getCachedValueTable(final String tableName) {
        return Iterables.find(super.getValueTables(), new Predicate<ValueTable>() {
            @Override
            public boolean apply(ValueTable input) {
                return tableName.equals(input.getName());
            }
        });
    }

    private void addValueTable(String table) {
        ValueTable vt = initialiseValueTable(table);
        Initialisables.initialise(vt);
        addValueTable(vt);
    }

    OpalJavaClient getOpalClient() {
        return opalClient;
    }

    URI newReference(String... segments) {
        return uriBuilder().segment(segments).build();
    }

    UriBuilder newUri(String... segments) {
        return uriBuilder().segment(segments);
    }

    URI buildURI(URI root, String... segments) {
        return uriBuilder(root).segment(segments).build();
    }

    UriBuilder uriBuilder() {
        return uriBuilder(datasourceURI);
    }

    UriBuilder uriBuilder(URI root) {
        return opalClient.newUri(root);
    }

}