org.obiba.opal.web.identifiers.IdentifiersMappingResource.java Source code

Java tutorial

Introduction

Here is the source code for org.obiba.opal.web.identifiers.IdentifiersMappingResource.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.web.identifiers;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.List;
import java.util.NoSuchElementException;

import javax.annotation.Nullable;
import javax.validation.constraints.NotNull;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

import org.obiba.magma.Datasource;
import org.obiba.magma.DatasourceFactory;
import org.obiba.magma.MagmaEngine;
import org.obiba.magma.MagmaRuntimeException;
import org.obiba.magma.NoSuchDatasourceException;
import org.obiba.magma.NoSuchValueTableException;
import org.obiba.magma.ValueTable;
import org.obiba.magma.ValueTableWriter;
import org.obiba.magma.Variable;
import org.obiba.magma.datasource.csv.support.CsvDatasourceFactory;
import org.obiba.magma.support.Disposables;
import org.obiba.opal.core.identifiers.IdentifierGeneratorImpl;
import org.obiba.opal.core.identifiers.IdentifiersMapping;
import org.obiba.opal.core.identifiers.IdentifiersMaps;
import org.obiba.opal.core.runtime.OpalRuntime;
import org.obiba.opal.core.service.IdentifiersImportService;
import org.obiba.opal.core.service.IdentifiersTableService;
import org.obiba.opal.web.magma.ClientErrorDtos;
import org.obiba.opal.web.magma.Dtos;
import org.obiba.opal.web.magma.support.DatasourceFactoryRegistry;
import org.obiba.opal.web.model.Magma;
import org.obiba.opal.web.ws.security.AuthenticatedByCookie;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;

import au.com.bytecode.opencsv.CSVWriter;

@Component
@Transactional
@Scope("request")
@Path("/identifiers/mapping/{name}")
@Api(value = "/identifiers/mapping/{name}", description = "Operations about a specific identifiers mapping")
public class IdentifiersMappingResource extends AbstractIdentifiersResource {

    @Autowired
    private OpalRuntime opalRuntime;

    @Autowired
    private IdentifiersTableService identifiersTableService;

    @Autowired
    private IdentifiersImportService identifiersImportService;

    @Autowired
    private DatasourceFactoryRegistry datasourceFactoryRegistry;

    @PathParam("name")
    private String name;

    @Override
    protected IdentifiersTableService getIdentifiersTableService() {
        return identifiersTableService;
    }

    @Override
    protected OpalRuntime getOpalRuntime() {
        return opalRuntime;
    }

    @GET
    @ApiOperation(value = "Get a specific identifiers mapping for an entity type")
    public Magma.VariableDto get(@QueryParam("type") String entityType) {
        ensureEntityType(entityType);
        ValueTable table = getValueTable(entityType);
        Variable variable = table.getVariable(name);

        return Dtos.asDto(variable).build();
    }

    @DELETE
    @ApiOperation(value = "Delete a specific identifiers mapping for an entity type")
    public Response delete(@QueryParam("type") String entityType) {
        ensureEntityType(entityType);

        ValueTable table = getValueTable(entityType);
        // The variable must exist
        Variable v = table.getVariable(name);
        try (ValueTableWriter tableWriter = table.getDatasource().createWriter(table.getName(),
                table.getEntityType());
                ValueTableWriter.VariableWriter variableWriter = tableWriter.writeVariables()) {
            variableWriter.removeVariable(v);
            return Response.ok().build();
        }
    }

    @GET
    @Path("/entities")
    @ApiOperation(value = "Get identifiers as entities")
    public List<Magma.VariableEntityDto> getUnitEntities(@QueryParam("type") String entityType) {
        ensureEntityType(entityType);
        return Lists.newArrayList(
                Iterables.transform(new IdentifiersMaps(getValueTable(entityType), name).getPrivateEntities(),
                        Dtos.variableEntityAsDtoFunc));
    }

    @GET
    @Path("/_count")
    public String getEntitiesCount(@QueryParam("type") String entityType) {
        ensureEntityType(entityType);
        return String.valueOf(Iterables.size(getUnitIdentifiers(entityType)));
    }

    /**
     * Copy the provided identifiers mapping into the corresponding identifiers table. New system identifiers will be
     * added, existing mapped identifiers will be overridden.
     *
     * @param entityType
     * @param separator
     * @param identifiersMap
     * @return
     */
    @POST
    @Consumes("text/plain")
    @Path("/_import")
    public Response importIdentifiers(@QueryParam("type") String entityType,
            @QueryParam("separator") @DefaultValue(",") String separator, String identifiersMap) {
        ensureEntityType(entityType);
        Response response = null;
        File csvData = null;
        try {
            CsvDatasourceFactory factory = new CsvDatasourceFactory();
            csvData = File.createTempFile("opal", ".csv");
            PrintWriter writer = new PrintWriter(csvData);
            writer.println("ID" + separator + name);
            writer.print(identifiersMap);
            writer.flush();
            writer.close();
            factory.setSeparator(separator);
            factory.addTable(entityType, csvData, entityType);
            response = copyIdentifiers(createTransientDatasource(factory));

        } catch (IOException e) {
            response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ClientErrorDtos
                    .getErrorMessage(Response.Status.INTERNAL_SERVER_ERROR, "DatasourceCopierIOException", e))
                    .build();
        } finally {
            if (csvData != null)
                csvData.delete();
        }

        return response;
    }

    @POST
    @Path("/_import")
    public Response importIdentifiers(Magma.DatasourceFactoryDto datasourceFactoryDto,
            @QueryParam("type") String entityType, @QueryParam("select") String select) {
        ensureEntityType(entityType);
        return importIdentifiers(createTransientDatasource(datasourceFactoryDto), entityType, select);
    }

    /**
     * Generate identifiers.
     *
     * @param entityType
     * @param size
     * @param zeros
     * @param prefix
     * @return
     */
    @POST
    @Path("/_generate")
    public Response importIdentifiers(@QueryParam("type") String entityType, @QueryParam("size") Integer size,
            @QueryParam("zeros") Boolean zeros, @QueryParam("prefix") String prefix) {
        ensureEntityType(entityType);
        try {
            IdentifierGeneratorImpl pId = new IdentifierGeneratorImpl();
            if (size != null)
                pId.setKeySize(size);
            if (zeros != null)
                pId.setAllowStartWithZero(zeros);
            if (prefix != null)
                pId.setPrefix(prefix);
            int count = identifiersImportService.importIdentifiers(new IdentifiersMapping(name, entityType), pId);
            return Response.ok().entity(Integer.toString(count)).build();
        } catch (MagmaRuntimeException ex) {
            return Response
                    .status(Response.Status.INTERNAL_SERVER_ERROR).entity(ClientErrorDtos
                            .getErrorMessage(Response.Status.INTERNAL_SERVER_ERROR, "ImportIdentifiersError", ex))
                    .build();
        }
    }

    /**
     * Get the non-null values of a variable's vector in CSV format.
     *
     * @return
     * @throws org.obiba.magma.MagmaRuntimeException
     * @throws java.io.IOException
     */
    @GET
    @Path("/_export")
    @Produces("text/csv")
    @AuthenticatedByCookie
    @ApiOperation(value = "Get identifiers mapping in CSV", produces = "text/csv")
    public Response getVectorCSVValues(@QueryParam("type") String entityType)
            throws MagmaRuntimeException, IOException {
        ensureEntityType(entityType);
        ValueTable table = getValueTable(entityType);
        Variable variable = table.getVariable(name);

        ByteArrayOutputStream values = new ByteArrayOutputStream();
        CSVWriter writer = null;
        try {
            writer = new CSVWriter(new PrintWriter(values));
            writeCSVValues(writer, table, variable);
        } finally {
            if (writer != null)
                writer.close();
        }

        return Response.ok(values.toByteArray(), "text/csv").header("Content-Disposition",
                "attachment; filename=\"" + table.getName() + "-" + variable.getName() + ".csv\"").build();
    }

    /**
     * Get the non-null values of a variable's vector in plain format.
     *
     * @return
     * @throws MagmaRuntimeException
     * @throws IOException
     */
    @GET
    @Path("/entities/_export")
    @Produces("text/plain")
    @AuthenticatedByCookie
    @ApiOperation(value = "Get identifiers in plain text", produces = "text/plain")
    public Response getVectorValues(@QueryParam("type") String entityType)
            throws MagmaRuntimeException, IOException {
        ensureEntityType(entityType);
        ValueTable table = getValueTable(entityType);
        Variable variable = table.getVariable(name);

        ByteArrayOutputStream values = new ByteArrayOutputStream();
        Writer writer = null;
        try {
            writer = new PrintWriter(values);
            writePlainValues(writer, table);
        } finally {
            if (writer != null)
                writer.close();
        }

        return Response.ok(values.toByteArray(), "text/plain").header("Content-Disposition",
                "attachment; filename=\"" + table.getName() + "-" + variable.getName() + ".txt\"").build();
    }

    //
    // Private methods
    //

    private Response importIdentifiers(Datasource sourceDatasource, String entityType, String select) {
        Response response = null;
        try {
            identifiersImportService.importIdentifiers(new IdentifiersMapping(name, entityType), sourceDatasource,
                    select);
            response = Response.ok().build();
        } catch (NoSuchDatasourceException ex) {
            response = Response.status(Response.Status.NOT_FOUND)
                    .entity(ClientErrorDtos.getErrorMessage(Response.Status.NOT_FOUND, "DatasourceNotFound", ex))
                    .build();
        } catch (NoSuchValueTableException ex) {
            response = Response.status(Response.Status.NOT_FOUND)
                    .entity(ClientErrorDtos.getErrorMessage(Response.Status.NOT_FOUND, "ValueTableNotFound", ex))
                    .build();
        } catch (IOException ex) {
            response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ClientErrorDtos
                    .getErrorMessage(Response.Status.INTERNAL_SERVER_ERROR, "DatasourceCopierIOException", ex))
                    .build();
        } finally {
            Disposables.silentlyDispose(sourceDatasource);
        }

        return response;
    }

    private Response copyIdentifiers(Datasource identifiersDatasource) {
        Response response = null;
        try {
            for (ValueTable identifiersTable : identifiersDatasource.getValueTables()) {
                identifiersImportService.copyIdentifiers(identifiersTable);
            }
            response = Response.ok().build();
        } catch (NoSuchDatasourceException ex) {
            response = Response.status(Response.Status.NOT_FOUND)
                    .entity(ClientErrorDtos.getErrorMessage(Response.Status.NOT_FOUND, "DatasourceNotFound", ex))
                    .build();
        } catch (NoSuchValueTableException ex) {
            response = Response.status(Response.Status.NOT_FOUND)
                    .entity(ClientErrorDtos.getErrorMessage(Response.Status.NOT_FOUND, "ValueTableNotFound", ex))
                    .build();
        } catch (IOException ex) {
            response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ClientErrorDtos
                    .getErrorMessage(Response.Status.INTERNAL_SERVER_ERROR, "DatasourceCopierIOException", ex))
                    .build();
        } finally {
            Disposables.silentlyDispose(identifiersDatasource);
        }

        return response;
    }

    private Datasource createTransientDatasource(Magma.DatasourceFactoryDto datasourceFactoryDto) {
        return createTransientDatasource(datasourceFactoryRegistry.parse(datasourceFactoryDto));
    }

    private Datasource createTransientDatasource(DatasourceFactory factory) {
        String uid = MagmaEngine.get().addTransientDatasource(factory);

        return MagmaEngine.get().getTransientDatasourceInstance(uid);
    }

    private Iterable<IdentifiersMaps.IdentifiersMap> getUnitIdentifiers(String entityType) {
        return Iterables.filter(new IdentifiersMaps(getValueTable(entityType), name),
                new Predicate<IdentifiersMaps.IdentifiersMap>() {
                    @Override
                    public boolean apply(@Nullable IdentifiersMaps.IdentifiersMap input) {
                        return input != null && input.hasPrivateIdentifier();
                    }
                });
    }

    @Override
    @NotNull
    protected ValueTable getValueTable(@NotNull String entityType) {
        ValueTable table = super.getValueTable(entityType);
        if (table == null)
            throw new NoSuchElementException("No identifiers mapping found for entity type: " + entityType);
        return table;
    }

    private void writeCSVValues(CSVWriter writer, ValueTable table, Variable variable) {
        // header
        writer.writeNext(new String[] { table.getEntityType(), variable.getName() });
        for (IdentifiersMaps.IdentifiersMap unitId : getUnitIdentifiers(table.getEntityType())) {
            writer.writeNext(new String[] { unitId.getSystemIdentifier(), unitId.getPrivateIdentifier() });
        }
    }

    private void writePlainValues(Writer writer, ValueTable table) throws IOException {
        for (IdentifiersMaps.IdentifiersMap unitId : getUnitIdentifiers(table.getEntityType())) {
            writer.write(unitId.getPrivateIdentifier() + "\n");
        }
    }

}