diff --git a/README.md b/README.md
index 15002cd..c74a838 100644
--- a/README.md
+++ b/README.md
@@ -9,42 +9,23 @@
* [How it works](#how-it-works)
* [Technologies](#technologies)
-##What it is
-This project contains the BDK (beacon development kit) for Java (EE) developers. The BDK provides all of the tools required to create a basic rest implementation for a beacon almost straight out of the box with only minimal set up required.
-Users can extend the BDK to make it fit within their own project, or use it as is defining their own adapter to retrieve data from their preferred data source.
-
-##System requirements
-All you need to build this project is Java 8.0 (Java SDK 1.8) or later, Maven 3.0 or later. Since the project is Java EE based, an application server with support for Java EE 7 is needed to deploy the application (e.g. JBoss EAP or WildFly).
-
-##Modules
-1. [beacon-java-core](/beacon-java-core)
- Contains core classes and functions shared across modules in the BJDK.
-2. [beacon-java-rest](/beacon-java-rest)
- Rest implementation of a beacon, configured to run on a JBOSS server.
-3. [sample-beacon-adapter](/sample-beacon-adapter)
- Sample beacon adapter implementation
-
-## Beacon Specification
-The BDK implements the beacon specification and relies on the data models generated by the beacon schema. At the moment the dependency is not currently listed on maven central but can be retrived from the [beacon teams git hub repository](https://github.com/ga4gh/beacon-team).
-
-To retrieve the dependency:
-
-```
-git clone https://github.com/ga4gh/beacon-team
-cd beacon-team
-mvn clean install
-```
-
-## How it Works
-The project provides the following:
-
-- API for beacons
-- sample beacon implementation
-- conversion of parameters to a normalized form (the same way Beacon of Beacons does)
-- sample navigation webpage
-- sample test suite
-
-##How to run it
+## What it is
+This project contains the BDK (beacon development kit) for Java EE developers. The BDK provides all of the tools required
+to create a basic rest implementation for a beacon almost straight out of the box with only minimal set up required.
+Extend the BDK to make it fit within their own project, or use it as is defining your own adapter to retrieve data from
+your preferred data source.
+
+## System Requirements
+- Java 8 or later;
+- Maven 3.0 or later;
+- [Beacon Schemas (v.0.3.0)](https://github.com/ga4gh/beacon-team): BDK relies on the generated Java classes;
+- an application server with support for Java EE 7 (e.g. JBoss EAP or WildFly).
+
+## Modules
+- [beacon-java-rest](/beacon-java-rest): rest implementation of a beacon, configured to run on a JBoss server;
+- [sample-beacon-adapter](/sample-beacon-adapter): sample beacon adapter implementation.
+
+## How to run it
Build the project:
mvn clean install
@@ -63,20 +44,20 @@ In order to run the tests from beacon-java-rest in a managed (remote) container,
mvn test -Ptest-managed
-##Creating a beacon
-The beacon implementation is designed to use a beacon-adapter provided through the [beacon-adapter-api project](https://github.com/mcupak/beacon-adapter-api) project. The user can either extend the abstract BeaconAdapter class to create a custom implementation, or they can use one of the beacon-adapter implementations that are provided
+## Creating a Beacon
+Beacon REST API uses Beacon Adapter to retrieve the beacon data. The BDK ships with a sample Beacon Adapter that uses
+sample data. The sample Beacon Adapter is intended to be a placeholder to allow the tests to be run, and to give the user
+an idea of how to implement a beacon.
-Once you have created your own adapter, simply replace the adapter dependency in the beacon-java-rest's pom with your own. The sample beacon adapter is intended to be a placeholder to allow the tests to be run, and to give the user an idea of how to implement a beacon. After this has been completely they are free to implement their own adapter.
+Once you are ready, implement your own [beacon-adapter](https://github.com/mcupak/beacon-service) project to query your
+own data. To switch to your own Beacon Adapter, simply replace the adapter dependency in the beacon-java-rest's pom with
+your own.
-- Add your desired beacon adapter to the pom.xml in the commented out section
-- Deploy The beacon
-- Run the test-managed profile to ensure the beacon works and complies with the beacon spec
-
-The API takes care of the rest and provides the following endpoints upon deployment of your beacon:
+The Rest API provides the following endpoints upon deployment of your beacon:
http://localhost:8080/beacon-java - information about your beacon
http://localhost:8080/beacon-java/query - access to query service
-##Technologies
-Java EE. CDI, JAX-RS, JAXB. Tested with Arquillian/ShrinkWrap.
+## Technologies
+Java EE. CDI, JAX-RS, JAXB. Tested with Arquillian/ShrinkWrap.
\ No newline at end of file
diff --git a/beacon-java-rest/pom.xml b/beacon-java-rest/pom.xml
index 8a7a415..cf99540 100644
--- a/beacon-java-rest/pom.xml
+++ b/beacon-java-rest/pom.xml
@@ -9,13 +9,11 @@
1.0-SNAPSHOT
-
- com.dnastackbeacon-java-rest1.0-SNAPSHOTwar
- beacon-java-rest
+ Beacon Java Rest
@@ -109,23 +107,29 @@
test
- com.dnastack
- beacon-java-service
- ${project.version}
+ org.keycloak
+ keycloak-servlet-filter-adapter
+
+
+ org.keycloak
+ keycloak-authz-client
+
+
+
+ org.apache.httpcomponents
+ httpclientcom.dnastackbeacon-adapter-api
+ ${version.beacon.adapter.api}
-
-
+
com.dnastacksample-beacon-adapter${project.version}
-
-
@@ -140,6 +144,9 @@
org.wildfly.pluginswildfly-maven-plugin
+
+ 10090
+ maven-compiler-plugin
@@ -160,16 +167,12 @@
+ org.apache.maven.pluginsmaven-surefire-plugin
- ${version.surefire.plugin}true
-
- org.wildfly.plugins
- wildfly-maven-plugin
-
@@ -181,17 +184,36 @@
wildfly-arquillian-container-managedtest
-
- org.jboss.arquillian.protocol
- arquillian-protocol-servlet
- test
-
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ unpack
+ process-test-classes
+
+ unpack
+
+
+
+
+ org.wildfly
+ wildfly-dist
+ ${version.org.wildfly}
+ zip
+ false
+ ${project.build.directory}
+
+
+
+
+
+ maven-surefire-plugin
- ${version.surefire.plugin}false
@@ -220,7 +242,6 @@
maven-surefire-plugin
- ${version.surefire.plugin}false
diff --git a/beacon-java-rest/src/main/java/com/dnastack/beacon/providers/BeaconExceptionHandler.java b/beacon-java-rest/src/main/java/com/dnastack/beacon/providers/BeaconExceptionHandler.java
deleted file mode 100644
index 6d98a3a..0000000
--- a/beacon-java-rest/src/main/java/com/dnastack/beacon/providers/BeaconExceptionHandler.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * The MIT License
- *
- * Copyright 2014 Miroslav Cupak (mirocupak@gmail.com).
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-package com.dnastack.beacon.providers;
-
-import com.dnastack.beacon.exceptions.BeaconAlleleRequestException;
-import com.dnastack.beacon.exceptions.BeaconException;
-import com.dnastack.beacon.service.api.BeaconService;
-import org.ga4gh.beacon.Beacon;
-import org.ga4gh.beacon.BeaconAlleleResponse;
-import org.ga4gh.beacon.BeaconError;
-
-import javax.inject.Inject;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-/**
- * Beacon exceptions handler for catching beacon errors and returning the appropriate object
- *
- * @author patmagee
- */
-@Provider
-public class BeaconExceptionHandler implements ExceptionMapper {
-
- @Inject
- BeaconService service;
-
- @Override
- public Response toResponse(BeaconException exception) {
-
- BeaconError error = new BeaconError();
- error.setMessage(exception.getMessage());
- switch (exception.getReason()) {
- case INVALID_REQUEST:
- error.setErrorCode(Response.Status.BAD_REQUEST.getStatusCode());
- break;
- default:
- error.setErrorCode(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
- }
-
- //If this is an alleleRequest then return a BeaconAlleleResponse with the error fields set appropriately
- if (exception.getClass().getCanonicalName().equals(BeaconAlleleRequestException.class.getCanonicalName())) {
- BeaconAlleleRequestException e = (BeaconAlleleRequestException) exception;
- BeaconAlleleResponse response = new BeaconAlleleResponse();
- response.setExists(null);
- response.setError(error);
-
- if (e.getRequest() != null) {
- response.setAlleleRequest(e.getRequest());
- }
-
- try {
- Beacon beacon = service.queryBeacon();
- response.setBeaconId(beacon.getId());
- } catch (BeaconException ex) {
- response.setBeaconId(null);
- }
-
- return Response.status(error.getErrorCode()).entity(response).build();
-
- } else {
- BeaconError response = error;
- return Response.status(error.getErrorCode()).entity(error).build();
- }
- }
-}
diff --git a/beacon-java-rest/src/main/java/com/dnastack/beacon/application/BeaconApplication.java b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/BeaconApplication.java
similarity index 97%
rename from beacon-java-rest/src/main/java/com/dnastack/beacon/application/BeaconApplication.java
rename to beacon-java-rest/src/main/java/com/dnastack/beacon/rest/BeaconApplication.java
index 39db57e..0829cef 100644
--- a/beacon-java-rest/src/main/java/com/dnastack/beacon/application/BeaconApplication.java
+++ b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/BeaconApplication.java
@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-package com.dnastack.beacon.application;
+package com.dnastack.beacon.rest;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
diff --git a/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/api/BeaconInfo.java b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/endpoints/BeaconInfo.java
similarity index 90%
rename from beacon-java-rest/src/main/java/com/dnastack/beacon/rest/api/BeaconInfo.java
rename to beacon-java-rest/src/main/java/com/dnastack/beacon/rest/endpoints/BeaconInfo.java
index 08224d5..2de6587 100644
--- a/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/api/BeaconInfo.java
+++ b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/endpoints/BeaconInfo.java
@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-package com.dnastack.beacon.rest.api;
+package com.dnastack.beacon.rest.endpoints;
import com.dnastack.beacon.exceptions.BeaconException;
import org.ga4gh.beacon.Beacon;
@@ -32,20 +32,16 @@
import javax.ws.rs.core.MediaType;
/**
- * Beacon rest resource.
- *
* @author Miroslav Cupak (mirocupak@gmail.com)
* @author Patrick Magee (patrickmageee@gmail.com)
+ * @author Artem (tema.voskoboynick@gmail.com)
* @version 1.0
*/
@Path("/")
public interface BeaconInfo {
/**
- * Gets Information on the beacon
- *
- * @return Beacon represenation
- * @throws BeaconException
+ * Gets information on the beacon.
*/
@GET
@Produces({MediaType.APPLICATION_JSON})
diff --git a/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/api/BeaconQuery.java b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/endpoints/BeaconQuery.java
similarity index 52%
rename from beacon-java-rest/src/main/java/com/dnastack/beacon/rest/api/BeaconQuery.java
rename to beacon-java-rest/src/main/java/com/dnastack/beacon/rest/endpoints/BeaconQuery.java
index 99333bd..ebfacae 100644
--- a/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/api/BeaconQuery.java
+++ b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/endpoints/BeaconQuery.java
@@ -21,21 +21,24 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-package com.dnastack.beacon.rest.api;
+package com.dnastack.beacon.rest.endpoints;
import com.dnastack.beacon.exceptions.BeaconException;
import org.ga4gh.beacon.BeaconAlleleRequest;
import org.ga4gh.beacon.BeaconAlleleResponse;
+import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import java.util.List;
/**
- * Beacon rest resource for querying alle information from a beacon
+ * Beacon rest resource for querying allele information from a beacon.
*
* @author Miroslav Cupak (mirocupak@gmail.com)
* @author Patrick Magee (patrickmageee@gmail.com)
+ * @author Artem (tema.voskoboynick@gmail.com)
* @version 1.0
*/
@Path("/query")
@@ -43,35 +46,39 @@ public interface BeaconQuery {
/**
* Query a beacon resource for information on whether an allele exists or not. Optionally includes the datasets.
- * Returns the completed BeaconAlleleResponse, Or a BeaconAlleleResponse with a BeaconError object if an error
+ * Returns the completed BeaconAlleleResponse or a BeaconAlleleResponse with a BeaconError object if an error
* was encountered.
*
- * @param referenceName Name of the chromosome or contig
+ * @param referenceName reference name (chromosome). Accepted values: 1-22, X, Y
* @param start 0-base start position
- * @param referenceBases String of reference bases
- * @param alternateBases String of alternate bases
- * @param assemblyId String of assembly build version
- * @param datasetIds List of dataset Ids
- * @param includeDatasetResponses Boolean value to include Dataset responses
- * @return Completed Beacon response object
- * @throws BeaconException
+ * @param referenceBases reference bases for this variant (starting from `start`). Accepted values: see the
+ * REF field in VCF 4.2 specification (https://samtools.github.io/hts-specs/VCFv4.2.pdf)
+ * @param alternateBases the bases that appear instead of the reference bases. Accepted values: see the ALT
+ * field in VCF 4.2 specification (https://samtools.github.io/hts-specs/VCFv4.2.pdf)
+ * @param assemblyId assembly identifier (GRC notation, e.g. `GRCh37`)
+ * @param datasetIds identifiers of datasets. If this field is null, all datasets will be queried
+ * @param includeDatasetResponses indicator of whether responses for individual datasets should be included (not null)
+ * in the response. If null, the default value of false is assumed
*/
@GET
@Produces({MediaType.APPLICATION_JSON})
- BeaconAlleleResponse query(@QueryParam("referenceName") String referenceName, @QueryParam("start") Long start, @QueryParam("referenceBases") String referenceBases, @QueryParam("alternateBases") String alternateBases, @QueryParam("assemblyId") String assemblyId, @QueryParam("datasetIds") List datasetIds, @QueryParam("includeDatasetResponses") Boolean includeDatasetResponses) throws BeaconException;
+ BeaconAlleleResponse query(@QueryParam("referenceName") String referenceName,
+ @QueryParam("start") Long start,
+ @QueryParam("referenceBases") String referenceBases,
+ @QueryParam("alternateBases") String alternateBases,
+ @QueryParam("assemblyId") String assemblyId,
+ @QueryParam("datasetIds") List datasetIds,
+ @QueryParam("includeDatasetResponses") Boolean includeDatasetResponses,
+ @Context HttpServletRequest servletRequest) throws BeaconException;
/**
* Query a beacon resource for information on whether an allele exists or not. Optionally includes the datasets.
* Returns the completed BeaconAlleleResponse, Or a BeaconAlleleResponse with a BeaconError object if an error
* was encountered.
- *
- * @param request Completed Beacon response object
- * @return
- * @throws BeaconException
*/
@POST
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
- BeaconAlleleResponse query(BeaconAlleleRequest request) throws BeaconException;
+ BeaconAlleleResponse query(BeaconAlleleRequest request, @Context HttpServletRequest servletRequest) throws BeaconException;
}
diff --git a/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/impl/BeaconInfoImpl.java b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/endpoints/impl/BeaconInfoImpl.java
similarity index 77%
rename from beacon-java-rest/src/main/java/com/dnastack/beacon/rest/impl/BeaconInfoImpl.java
rename to beacon-java-rest/src/main/java/com/dnastack/beacon/rest/endpoints/impl/BeaconInfoImpl.java
index 1536a9d..fd97da5 100644
--- a/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/impl/BeaconInfoImpl.java
+++ b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/endpoints/impl/BeaconInfoImpl.java
@@ -21,30 +21,32 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-package com.dnastack.beacon.rest.impl;
+package com.dnastack.beacon.rest.endpoints.impl;
+import com.dnastack.beacon.adapter.api.BeaconAdapter;
import com.dnastack.beacon.exceptions.BeaconException;
-import com.dnastack.beacon.rest.api.BeaconInfo;
-import com.dnastack.beacon.service.api.BeaconService;
+import com.dnastack.beacon.rest.endpoints.BeaconInfo;
import org.ga4gh.beacon.Beacon;
import javax.inject.Inject;
+import javax.ws.rs.GET;
import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
/**
- * Beacon Info Implementation
+ * @author Artem (tema.voskoboynick@gmail.com)
*/
@Path("/")
public class BeaconInfoImpl implements BeaconInfo {
@Inject
- private BeaconService service;
+ private BeaconAdapter adapter;
- /**
- * {@inheritDoc}
- */
+ @GET
@Override
+ @Produces({MediaType.APPLICATION_JSON})
public Beacon info() throws BeaconException {
- return service.queryBeacon();
+ return adapter.getBeacon();
}
}
diff --git a/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/endpoints/impl/BeaconQueryImpl.java b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/endpoints/impl/BeaconQueryImpl.java
new file mode 100644
index 0000000..7b10820
--- /dev/null
+++ b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/endpoints/impl/BeaconQueryImpl.java
@@ -0,0 +1,114 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2014 Miroslav Cupak (mirocupak@gmail.com).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.dnastack.beacon.rest.endpoints.impl;
+
+import com.dnastack.beacon.adapter.api.BeaconAdapter;
+import com.dnastack.beacon.exceptions.BeaconAlleleRequestException;
+import com.dnastack.beacon.exceptions.BeaconException;
+import com.dnastack.beacon.rest.endpoints.BeaconQuery;
+import com.dnastack.beacon.utils.Reason;
+import org.apache.commons.lang.BooleanUtils;
+import org.apache.commons.lang.StringUtils;
+import org.ga4gh.beacon.BeaconAlleleRequest;
+import org.ga4gh.beacon.BeaconAlleleResponse;
+
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
+import java.util.List;
+
+/**
+ * @author Artem (tema.voskoboynick@gmail.com)
+ * @author Patrick Magee (patrickmageee@gmail.com)
+ */
+@Path("/query")
+public class BeaconQueryImpl implements BeaconQuery {
+
+ @Inject
+ private BeaconAdapter adapter;
+
+ @Override
+ public BeaconAlleleResponse query(String referenceName, Long start, String referenceBases, String alternateBases,
+ String assemblyId, List datasetIds, Boolean includeDatasetResponses, @Context HttpServletRequest servletRequest)
+ throws BeaconException {
+ validateRequest(referenceName, start, referenceBases, alternateBases, assemblyId);
+ BeaconAlleleRequest request = BeaconAlleleRequest.newBuilder()
+ .setReferenceName(referenceName)
+ .setStart(start)
+ .setReferenceBases(referenceBases)
+ .setAlternateBases(alternateBases)
+ .setAssemblyId(assemblyId)
+ .setDatasetIds(datasetIds)
+ .setIncludeDatasetResponses(BooleanUtils.isTrue(includeDatasetResponses))
+ .build();
+
+ return adapter.getBeaconAlleleResponse(request);
+ }
+
+ @Override
+ public BeaconAlleleResponse query(BeaconAlleleRequest request, @Context HttpServletRequest servletRequest) throws BeaconException {
+ validateRequest(request);
+ return adapter.getBeaconAlleleResponse(request);
+ }
+
+ private void validateRequest(BeaconAlleleRequest request) throws BeaconAlleleRequestException {
+ throwIf(request == null, "Request can't be null", request);
+ try {
+ validateRequest(request.getReferenceName(), request.getStart(), request.getReferenceBases(), request.getAlternateBases(), request.getAssemblyId());
+ } catch (BeaconAlleleRequestException e) {
+ e.setRequest(request);
+ throw e;
+ }
+ }
+
+ /**
+ * Validates the request parameters according to the 0.3.0 beacon specifications.
+ */
+ private void validateRequest(String referenceName, Long start, String referenceBases, String alternateBases, String assemblyId) throws BeaconAlleleRequestException {
+ boolean isValidReferenceName = StringUtils.isNotBlank(referenceName);
+ boolean isValidStart = start != null && start >= 0;
+ boolean isValidReferenceBases = StringUtils.isNotBlank(referenceBases);
+ boolean isValidAlternateBases = StringUtils.isNotBlank(alternateBases);
+ boolean isValidAssemblyId = StringUtils.startsWith(assemblyId, "GRCh");
+
+ throwIf(!isValidReferenceName, "Reference name can't be null");
+ throwIf(!isValidStart, "Start position can't be null, should be 0-based positive integer");
+ throwIf(!isValidReferenceBases, "Reference bases can't be null");
+ throwIf(!isValidAlternateBases, "Alternate bases can't be null");
+ throwIf(!isValidAssemblyId, "Assembly ID can't be null, should start with GRCh");
+ }
+
+ private static void throwIf(boolean expression, String message) throws BeaconAlleleRequestException {
+ if (expression) {
+ throw new BeaconAlleleRequestException(Reason.INVALID_REQUEST, message);
+ }
+ }
+
+ private static void throwIf(boolean expression, String message, BeaconAlleleRequest request) throws BeaconAlleleRequestException {
+ if (expression) {
+ throw new BeaconAlleleRequestException(message, Reason.INVALID_REQUEST, request);
+ }
+ }
+}
diff --git a/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/endpoints/impl/secured/SecuredBeaconQueryImpl.java b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/endpoints/impl/secured/SecuredBeaconQueryImpl.java
new file mode 100644
index 0000000..bb76dd4
--- /dev/null
+++ b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/endpoints/impl/secured/SecuredBeaconQueryImpl.java
@@ -0,0 +1,105 @@
+package com.dnastack.beacon.rest.endpoints.impl.secured;
+
+import com.dnastack.beacon.exceptions.BeaconException;
+import com.dnastack.beacon.rest.endpoints.BeaconQuery;
+import com.dnastack.beacon.rest.endpoints.impl.BeaconQueryImpl;
+import com.dnastack.beacon.rest.sys.security.SecurityContext;
+import org.apache.commons.collections.CollectionUtils;
+import org.ga4gh.beacon.BeaconAlleleRequest;
+import org.ga4gh.beacon.BeaconAlleleResponse;
+import org.ga4gh.beacon.BeaconDatasetAlleleResponse;
+import org.keycloak.AuthorizationContext;
+import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.representations.authorization.Permission;
+
+import javax.decorator.Decorator;
+import javax.decorator.Delegate;
+import javax.enterprise.inject.Any;
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Context;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Decorates the original {@link BeaconQueryImpl} to enforce security constraints.
+ * Role-based access is automatically checked by the Keycloak filter, this class handles more detailed security constraints.
+ *
+ * @author Artem (tema.voskoboynick@gmail.com)
+ * @version 1.0
+ */
+@Decorator
+public class SecuredBeaconQueryImpl implements BeaconQuery {
+
+ /**
+ * Public role is like an admin role - can view anything.
+ */
+ private static final String PUBLIC_ROLE = "public";
+
+ /**
+ * Users with Registered role are allowed to view only answers yes/no.
+ * But individual users are allowed to view individual dataset responses.
+ */
+ private static final String REGISTERED_ROLE = "registered";
+
+ /**
+ * In Keycloak, a dataset resource name is in the "Dataset:[dataset_id]" format.
+ * Allowed dataset IDs are retrieved by removing the "Dataset:" prefix.
+ */
+ private static final String DATASET_RESOURCES_PREFIX = "Dataset:";
+
+ @Delegate
+ @Any
+ @Inject
+ private BeaconQuery delegate;
+
+ @Inject
+ private SecurityContext securityContext;
+
+ @Override
+ public BeaconAlleleResponse query(String referenceName, Long start, String referenceBases, String alternateBases, String assemblyId, List datasetIds, Boolean includeDatasetResponses, @Context HttpServletRequest servletRequest) throws BeaconException {
+ BeaconAlleleResponse response = delegate.query(referenceName, start, referenceBases, alternateBases, assemblyId, datasetIds, includeDatasetResponses, servletRequest);
+ ensureSecurityConstraints(servletRequest, response);
+ return response;
+ }
+
+ @Override
+ public BeaconAlleleResponse query(BeaconAlleleRequest request, @Context HttpServletRequest servletRequest) throws BeaconException {
+ BeaconAlleleResponse response = delegate.query(request, servletRequest);
+ ensureSecurityConstraints(servletRequest, response);
+ return response;
+ }
+
+ private void ensureSecurityConstraints(HttpServletRequest servletRequest, BeaconAlleleResponse response) {
+ if (!securityContext.isSecurityEnabled()) {
+ return;
+ }
+
+ if (servletRequest.isUserInRole(PUBLIC_ROLE)) {
+ return;
+ }
+
+ if (servletRequest.isUserInRole(REGISTERED_ROLE)) {
+ excludeUnauthorizedDatasets(servletRequest, response.getDatasetAlleleResponses());
+ }
+ }
+
+ private void excludeUnauthorizedDatasets(HttpServletRequest servletRequest, List datasetResponses) {
+ if (CollectionUtils.isNotEmpty(datasetResponses)) {
+ Set permittedDatasetIds = getPermittedDatasetIds(servletRequest);
+ datasetResponses.removeIf(datasetResponse -> !permittedDatasetIds.contains(datasetResponse.getDatasetId()));
+ }
+ }
+
+ private Set getPermittedDatasetIds(HttpServletRequest servletRequest) {
+ KeycloakSecurityContext keycloakSecurityContext = (KeycloakSecurityContext) servletRequest.getAttribute(KeycloakSecurityContext.class.getName());
+ AuthorizationContext authzContext = keycloakSecurityContext.getAuthorizationContext();
+
+ List permissions = authzContext.getPermissions();
+ return permissions.stream()
+ .filter(permission -> permission.getResourceSetName().startsWith(DATASET_RESOURCES_PREFIX))
+ .map(permission -> permission.getResourceSetName().substring(DATASET_RESOURCES_PREFIX.length()))
+ .collect(Collectors.toSet());
+ }
+}
diff --git a/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/impl/BeaconQueryImpl.java b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/impl/BeaconQueryImpl.java
deleted file mode 100644
index ff62f8d..0000000
--- a/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/impl/BeaconQueryImpl.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * The MIT License
- *
- * Copyright 2014 Miroslav Cupak (mirocupak@gmail.com).
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-package com.dnastack.beacon.rest.impl;
-
-import com.dnastack.beacon.exceptions.BeaconException;
-import com.dnastack.beacon.rest.api.BeaconQuery;
-import com.dnastack.beacon.service.api.BeaconService;
-import org.ga4gh.beacon.BeaconAlleleRequest;
-import org.ga4gh.beacon.BeaconAlleleResponse;
-
-import javax.inject.Inject;
-import javax.ws.rs.Path;
-import java.util.List;
-
-/**
- * Beacon Query Implementation
- */
-@Path("/query")
-public class BeaconQueryImpl implements BeaconQuery {
-
- @Inject
- private BeaconService service;
-
- /**
- * {@inheritDoc}
- */
- @Override
- public BeaconAlleleResponse query(String referenceName, Long start, String referenceBases, String alternateBases, String assemblyId, List datasetIds, Boolean includeDatasetResponses) throws BeaconException {
- return service.queryAllele(referenceName,
- start,
- referenceBases,
- alternateBases,
- assemblyId,
- datasetIds,
- includeDatasetResponses);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public BeaconAlleleResponse query(BeaconAlleleRequest request) throws BeaconException {
- return service.queryAllele(request);
- }
-}
diff --git a/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/sys/BeaconExceptionHandler.java b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/sys/BeaconExceptionHandler.java
new file mode 100644
index 0000000..aa56589
--- /dev/null
+++ b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/sys/BeaconExceptionHandler.java
@@ -0,0 +1,60 @@
+package com.dnastack.beacon.rest.sys;
+
+import com.dnastack.beacon.exceptions.BeaconAlleleRequestException;
+import com.dnastack.beacon.exceptions.BeaconException;
+import org.ga4gh.beacon.BeaconAlleleResponse;
+import org.ga4gh.beacon.BeaconError;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
+import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
+
+/**
+ * Captures all Beacon exceptions and creates corresponding responses.
+ *
+ * @author patmagee
+ * @author Artem (tema.voskoboynick@gmail.com)
+ * @version 1.0
+ */
+@Provider
+public class BeaconExceptionHandler implements ExceptionMapper {
+
+ @Override
+ public Response toResponse(BeaconException exception) {
+ if (exception instanceof BeaconAlleleRequestException) {
+ return handleBeaconAlleleRequestException((BeaconAlleleRequestException) exception);
+ } else {
+ return handleDefaultBeaconException(exception);
+ }
+ }
+
+ /**
+ * Due to backward compatibility issues, the response on Beacon Query request should always be of the {@link BeaconAlleleResponse} type,
+ * and any errors, if any, are stored inside it.
+ */
+ private Response handleBeaconAlleleRequestException(BeaconAlleleRequestException exception) {
+ BeaconAlleleResponse response = new BeaconAlleleResponse();
+ response.setAlleleRequest(exception.getRequest());
+ response.setExists(null);
+
+ BeaconError error = BeaconError.newBuilder()
+ .setErrorCode(BAD_REQUEST.getStatusCode())
+ .setMessage(exception.getMessage())
+ .build();
+ response.setError(error);
+
+ return Response.status(error.getErrorCode()).entity(response).build();
+ }
+
+ private Response handleDefaultBeaconException(BeaconException exception) {
+ BeaconError response = BeaconError.newBuilder()
+ .setMessage(exception.getMessage())
+ .setErrorCode(INTERNAL_SERVER_ERROR.getStatusCode())
+ .build();
+
+ return Response.status(response.getErrorCode()).entity(response).build();
+ }
+}
diff --git a/beacon-java-rest/src/main/java/com/dnastack/beacon/providers/DefaultExceptionHandler.java b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/sys/DefaultExceptionHandler.java
similarity index 61%
rename from beacon-java-rest/src/main/java/com/dnastack/beacon/providers/DefaultExceptionHandler.java
rename to beacon-java-rest/src/main/java/com/dnastack/beacon/rest/sys/DefaultExceptionHandler.java
index 8baa181..6915686 100644
--- a/beacon-java-rest/src/main/java/com/dnastack/beacon/providers/DefaultExceptionHandler.java
+++ b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/sys/DefaultExceptionHandler.java
@@ -21,40 +21,33 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-package com.dnastack.beacon.providers;
+package com.dnastack.beacon.rest.sys;
-import com.dnastack.beacon.util.ResponseMappingResource;
import org.ga4gh.beacon.BeaconError;
-import org.json.simple.JSONObject;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
+import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
+
/**
- * Default Exception handler to catch all Non Beacon exceptions thrown by the rest resources.z
+ * Catches all non Beacon exceptions thrown by the rest resources.
*
* @author patmagee
+ * @author Artem (tema.voskoboynick@gmail.com)
*/
@Provider
-public class DefaultExceptionHandler implements ExceptionMapper {
+public class DefaultExceptionHandler implements ExceptionMapper {
- /**
- * Default error handler to capture all errors and send the user a JSON response
- * with the status code, reason, message and stacktrace of the error
- *
- * @param e exceptions
- * @return response with the status and error entity
- */
@Override
- public Response toResponse(Exception e) {
- JSONObject json = new JSONObject();
- Response.Status s = ResponseMappingResource.getStatus(e);
+ public Response toResponse(Throwable exception) {
+ BeaconError response = BeaconError.newBuilder()
+ .setMessage(exception.getMessage())
+ .setErrorCode(INTERNAL_SERVER_ERROR.getStatusCode())
+ .build();
- BeaconError error = new BeaconError();
- error.setMessage(e.getMessage());
- error.setErrorCode(s.getStatusCode());
- return Response.status(s).entity(error).type(MediaType.APPLICATION_JSON_TYPE).build();
+ return Response.status(response.getErrorCode()).type(MediaType.APPLICATION_JSON).entity(response).build();
}
}
diff --git a/beacon-java-rest/src/main/java/com/dnastack/beacon/providers/GsonMessageBodyHandler.java b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/sys/GsonMessageBodyHandler.java
similarity index 62%
rename from beacon-java-rest/src/main/java/com/dnastack/beacon/providers/GsonMessageBodyHandler.java
rename to beacon-java-rest/src/main/java/com/dnastack/beacon/rest/sys/GsonMessageBodyHandler.java
index d8bed74..81d3b94 100644
--- a/beacon-java-rest/src/main/java/com/dnastack/beacon/providers/GsonMessageBodyHandler.java
+++ b/beacon-java-rest/src/main/java/com/dnastack/beacon/rest/sys/GsonMessageBodyHandler.java
@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-package com.dnastack.beacon.providers;
+package com.dnastack.beacon.rest.sys;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -37,11 +37,13 @@
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
/**
- * Gson Message Body Handler for serializing JSON data to and from auto generated Java classes
+ * Gson Message Body Handler for serializing JSON data to and from auto generated Java classes.
*
* @author patmagee
+ * @author Artem (tema.voskoboynick@gmail.com)
* @version 1.0
*/
@Provider
@@ -49,16 +51,8 @@
@Consumes(MediaType.APPLICATION_JSON)
public class GsonMessageBodyHandler implements MessageBodyReader
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${version.surefire.plugin}
+ maven-compiler-plugin${version.compiler.plugin}
diff --git a/sample-beacon-adapter/pom.xml b/sample-beacon-adapter/pom.xml
index d6e00a6..67ebff3 100644
--- a/sample-beacon-adapter/pom.xml
+++ b/sample-beacon-adapter/pom.xml
@@ -26,16 +26,16 @@
+ 4.0.0
+
beacon-javacom.dnastack1.0-SNAPSHOT
- 4.0.0
- sample-beacon-adapter
-
- jar
+ sample-beacon-adapter
+ Sample Beacon Adapter
@@ -58,15 +58,9 @@
beacon${version.beacon.api}
-
- com.dnastack
- beacon-java-service
- ${project.version}
- com.dnastackbeacon-adapter-api
- 1.0-SNAPSHOT
@@ -86,7 +80,4 @@
- sample-beacon-adapter
-
-
\ No newline at end of file
diff --git a/sample-beacon-adapter/src/main/java/com/dnastack/beacon/adapter/sample/SampleBeaconAdapter.java b/sample-beacon-adapter/src/main/java/com/dnastack/beacon/adapter/sample/SampleBeaconAdapter.java
new file mode 100644
index 0000000..1f54780
--- /dev/null
+++ b/sample-beacon-adapter/src/main/java/com/dnastack/beacon/adapter/sample/SampleBeaconAdapter.java
@@ -0,0 +1,180 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2014 Miroslav Cupak (mirocupak@gmail.com).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.dnastack.beacon.adapter.sample;
+
+import com.dnastack.beacon.adapter.api.BeaconAdapter;
+import com.dnastack.beacon.utils.AdapterConfig;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.BooleanUtils;
+import org.ga4gh.beacon.*;
+
+import javax.enterprise.context.Dependent;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static javax.ws.rs.core.Response.Status;
+
+/**
+ * Beacon adapter that returns sample data.
+ *
+ * @author Artem (tema.voskoboynick@gmail.com)
+ * @author Patrick Magee (patrickmageee@gmail.com)
+ */
+@Dependent
+public class SampleBeaconAdapter implements BeaconAdapter {
+
+ @Override
+ public Beacon getBeacon() {
+ return SampleData.BEACON;
+ }
+
+ @Override
+ public void initAdapter(AdapterConfig adapterConfig) {
+ }
+
+ @Override
+ public BeaconAlleleResponse getBeaconAlleleResponse(BeaconAlleleRequest request) {
+ BeaconAlleleResponse response = new BeaconAlleleResponse();
+ response.setBeaconId(SampleData.BEACON.getId());
+ response.setAlleleRequest(request);
+
+ DatasetsQueryResult datasetsResult = queryDatasets(request.getDatasetIds(), request.getAssemblyId(),
+ request.getReferenceName(), request.getStart(), request.getReferenceBases(), request.getAlternateBases());
+ response.setExists(datasetsResult.exists);
+ if (BooleanUtils.isTrue(request.getIncludeDatasetResponses())) {
+ response.setDatasetAlleleResponses(datasetsResult.responses);
+ }
+
+ return response;
+ }
+
+ @Override
+ public BeaconAlleleResponse getBeaconAlleleResponse(String referenceName, Long start, String referenceBases, String alternateBases, String assemblyId, List datasetIds, Boolean includeDatasetResponses) {
+ BeaconAlleleRequest request = createRequest(referenceName, start, referenceBases, alternateBases, assemblyId, datasetIds, includeDatasetResponses);
+ return getBeaconAlleleResponse(request);
+ }
+
+ private BeaconAlleleRequest createRequest(String referenceName, Long start, String referenceBases, String alternateBases, String assemblyId, List datasetIds, Boolean includeDatasetResponses) {
+ return BeaconAlleleRequest.newBuilder()
+ .setReferenceName(referenceName)
+ .setStart(start)
+ .setReferenceBases(referenceBases)
+ .setAlternateBases(alternateBases)
+ .setAssemblyId(assemblyId)
+ .setDatasetIds(datasetIds)
+ .setIncludeDatasetResponses(includeDatasetResponses)
+ .build();
+ }
+
+ private DatasetsQueryResult queryDatasets(List datasetIds, String assemblyId, String referenceName, Long start,
+ String referenceBases, String alternateBases) {
+ if (CollectionUtils.isEmpty(datasetIds)) {
+ // All datasets requested.
+ datasetIds = SampleData.DATASETS.keySet().stream().collect(Collectors.toList());
+ }
+
+ return doQueryDatasets(datasetIds, assemblyId, referenceName, start, referenceBases, alternateBases);
+ }
+
+ private DatasetsQueryResult doQueryDatasets(List datasetIds, String assemblyId, String referenceName, Long start,
+ String referenceBases, String alternateBases) {
+ DatasetsQueryResult datasetsResult = new DatasetsQueryResult();
+
+ for (String datasetId : datasetIds) {
+ BeaconDatasetAlleleResponse datasetResponse = queryDataset(datasetId, assemblyId, referenceName, start,
+ referenceBases, alternateBases);
+
+ // Find in descending priority: true, false, null.
+ Boolean existsInDataset = datasetResponse.getExists();
+ if (datasetsResult.exists == null || BooleanUtils.isTrue(existsInDataset)) {
+ datasetsResult.exists = existsInDataset;
+ }
+
+ // Collect any error, if exists.
+ if (datasetResponse.getError() != null) {
+ datasetsResult.error = datasetResponse.getError();
+ }
+
+ datasetsResult.responses.add(datasetResponse);
+ }
+
+ return datasetsResult;
+ }
+
+ @SuppressWarnings("unchecked")
+ private BeaconDatasetAlleleResponse queryDataset(String datasetId, String assemblyId, String referenceName, long start, String referenceBases, String alternateBases) {
+ Map dataset = SampleData.DATASETS.get(datasetId);
+ if (dataset == null) {
+ return createErrorDatasetResponse(datasetId, Status.NOT_FOUND.getStatusCode(), "Dataset not found");
+ }
+
+ Map assembly = dataset.get(assemblyId);
+ if (assembly == null) {
+ return createErrorDatasetResponse(datasetId, Status.NOT_FOUND.getStatusCode(), "Assembly not found");
+ }
+
+ Map reference = assembly.get(referenceName);
+ if (reference == null) {
+ return createErrorDatasetResponse(datasetId, Status.NOT_FOUND.getStatusCode(), "Reference not found");
+ }
+
+ Map bases = reference.get(start);
+ if (bases == null) {
+ return createSuccessfulDatasetResponse(datasetId, false);
+ }
+
+ if (bases.get("referenceBases").equals(referenceBases) && bases.get("alternateBases").equals(alternateBases)) {
+ return createSuccessfulDatasetResponse(datasetId, true);
+ } else {
+ return createSuccessfulDatasetResponse(datasetId, false);
+ }
+ }
+
+ private BeaconDatasetAlleleResponse createErrorDatasetResponse(String datasetId, int errorCode, String message) {
+ BeaconDatasetAlleleResponse response = new BeaconDatasetAlleleResponse();
+ response.setDatasetId(datasetId);
+
+ BeaconError error = BeaconError.newBuilder()
+ .setErrorCode(errorCode)
+ .setMessage(message).build();
+ response.setError(error);
+
+ return response;
+ }
+
+ private BeaconDatasetAlleleResponse createSuccessfulDatasetResponse(String datasetId, boolean exists) {
+ BeaconDatasetAlleleResponse response = BeaconDatasetAlleleResponse.newBuilder(SampleData.BASE_DATASET_RESPONSE).build();
+ response.setDatasetId(datasetId);
+ response.setExists(exists);
+ return response;
+ }
+
+ private static class DatasetsQueryResult {
+ Boolean exists;
+ BeaconError error;
+ List responses = new ArrayList<>();
+ }
+}
diff --git a/sample-beacon-adapter/src/main/java/com/dnastack/beacon/adapter/sample/SampleData.java b/sample-beacon-adapter/src/main/java/com/dnastack/beacon/adapter/sample/SampleData.java
new file mode 100644
index 0000000..a9de51b
--- /dev/null
+++ b/sample-beacon-adapter/src/main/java/com/dnastack/beacon/adapter/sample/SampleData.java
@@ -0,0 +1,127 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2014 Miroslav Cupak (mirocupak@gmail.com).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.dnastack.beacon.adapter.sample;
+
+import avro.shaded.com.google.common.collect.ImmutableMap;
+import org.ga4gh.beacon.*;
+
+import java.util.*;
+
+/**
+ * Sample data holder.
+ *
+ * @author patmagee
+ * @author Artem (tema.voskoboynick@gmail.com)
+ */
+public class SampleData {
+
+ public static final Map DATASETS;
+ public static final Beacon BEACON;
+ public static final BeaconDatasetAlleleResponse BASE_DATASET_RESPONSE;
+
+ static {
+ BeaconDataset dataset = BeaconDataset.newBuilder()
+ .setId("sample_dataset_id_1")
+ .setName("Sample Dataset")
+ .setAssemblyId("GRCh37")
+ .setUpdateDateTime(new Date().toString())
+ .setCreateDateTime(new Date().toString())
+ .setVersion("0.3.0")
+ .setCallCount(10L)
+ .setSampleCount(10L)
+ .setDescription("Sample implementation")
+ .setInfo(ImmutableMap.of("note", "This is a Sample Dataset"))
+ .build();
+
+ BeaconDataset dataset2 = BeaconDataset.newBuilder(dataset)
+ .setId("sample_dataset_id_2")
+ .setName("Second Sample Dataset")
+ .build();
+
+
+ BASE_DATASET_RESPONSE = BeaconDatasetAlleleResponse.newBuilder()
+ .setCallCount(1L)
+ .setFrequency(0.221)
+ .setVariantCount(1L)
+ .setSampleCount(1L)
+ .setExternalUrl("www.google.com")
+ .setInfo(ImmutableMap.of("Sample Note", "Sample Note Value"))
+ .setDatasetId(dataset.getId())
+ .setExists(null) // Setting nulls explicitly required by avro.
+ .build();
+
+ BeaconAlleleRequest sampleRequest = BeaconAlleleRequest.newBuilder()
+ .setDatasetIds(Arrays.asList(dataset.getId(), dataset2.getId()))
+ .setReferenceName("1")
+ .setAssemblyId("GRCh37")
+ .setIncludeDatasetResponses(true)
+ .setStart(1000L)
+ .setReferenceBases("A")
+ .setAlternateBases("C")
+ .build();
+
+ DATASETS = new HashMap() {
+ {
+ Map bases = ImmutableMap.of(
+ "referenceBases", sampleRequest.getReferenceBases(),
+ "alternateBases", sampleRequest.getAlternateBases()
+ );
+ Map positions = ImmutableMap.of(sampleRequest.getStart(), bases);
+ Map references = ImmutableMap.of(sampleRequest.getReferenceName(), positions);
+ Map assemblies = ImmutableMap.of(sampleRequest.getAssemblyId(), references);
+
+ put(dataset.getId(), assemblies);
+ put(dataset2.getId(), assemblies);
+ }
+ };
+
+ BeaconOrganization organization = BeaconOrganization.newBuilder()
+ .setAddress("123 Nullpointer Ave, StackTrace, Ohio")
+ .setContactUrl("www.google.com")
+ .setDescription("Sample implementation of a beacon organization")
+ .setWelcomeUrl("www.google.com")
+ .setLogoUrl("www.logoUrl.com")
+ .setName("Sample Organization")
+ .setId("sample_organization_id")
+ .setInfo(ImmutableMap.of("note", "This is a sample Organization"))
+ .build();
+
+ BEACON = Beacon.newBuilder()
+ .setApiVersion("0.3.0")
+ .setVersion("0.3.0")
+ .setDescription("Sample description")
+ .setName("Sample Beacon")
+ .setAlternativeUrl("www.google.ca")
+ .setWelcomeUrl("www.url")
+ .setDatasets(Collections.singletonList(dataset))
+ .setCreateDateTime(new Date().toString())
+ .setUpdateDateTime(new Date().toString())
+ .setSampleAlleleRequests(Collections.singletonList(sampleRequest))
+ .setOrganization(organization)
+ .setId("sample_beacon_id")
+ .setInfo(ImmutableMap.of("note", "This is a sample Beacon"))
+ .build();
+ }
+}
diff --git a/sample-beacon-adapter/src/main/java/com/dnastack/beacon/core/adapter/impl/SampleBeaconAdapterImpl.java b/sample-beacon-adapter/src/main/java/com/dnastack/beacon/core/adapter/impl/SampleBeaconAdapterImpl.java
deleted file mode 100644
index c436439..0000000
--- a/sample-beacon-adapter/src/main/java/com/dnastack/beacon/core/adapter/impl/SampleBeaconAdapterImpl.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * The MIT License
- *
- * Copyright 2014 Miroslav Cupak (mirocupak@gmail.com).
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-package com.dnastack.beacon.core.adapter.impl;
-
-import com.dnastack.beacon.adapter.api.BeaconAdapter;
-import com.dnastack.beacon.exceptions.BeaconException;
-import com.dnastack.beacon.utils.AdapterConfig;
-import org.ga4gh.beacon.*;
-
-import javax.annotation.PostConstruct;
-import javax.ejb.Singleton;
-import javax.enterprise.context.Dependent;
-import java.util.*;
-
-/**
- * @author patrickmagee
- */
-@Singleton
-public class SampleBeaconAdapterImpl implements BeaconAdapter {
-
- public static final String API_VERSION = "0.3.0";
- public static final String BEACON_ID = "beacon_id";
- public static final String DATASET_ID = "dataset_id";
- public static final String ORG_ID = "org_id";
-
- private SampleDataStore dataStore;
-
- private BeaconDatasetAlleleResponse lookupDataset(String datasetId, String assemblyId, String referencName, long start, String refBases, String altBases) {
- BeaconDatasetAlleleResponse response = new BeaconDatasetAlleleResponse();
- response.setDatasetId(datasetId);
-
- Map dataset = dataStore.getDATA().get(datasetId);
- if (dataset == null || dataset.isEmpty()) {
- BeaconError be = new BeaconError();
- be.setErrorCode(404);
- be.setMessage("Could not find dataset");
-
- response.setExists(null);
- response.setError(be);
-
- return response;
- }
- Map assembly = ((Map) dataset.get(assemblyId));
- if (assembly == null || assembly.isEmpty()) {
- BeaconError be = new BeaconError();
- be.setErrorCode(404);
- be.setMessage("Could not find assembly in current dataset");
-
- response.setExists(null);
- response.setError(be);
-
- return response;
- }
- Map reference = ((Map) assembly.get(referencName));
- if (reference == null || reference.isEmpty()) {
- response.setExists(null);
- return addInfo(response);
- }
- Map bases = ((Map) reference.get(start));
- if (bases == null || bases.isEmpty()) {
- response.setExists(false);
- return addInfo(response);
- }
- if (bases.get("referenceBases").equals(refBases) && bases.get("alternateBases").equals(altBases)) {
- response.setExists(true);
- return addInfo(response);
- } else {
- response.setExists(false);
- return addInfo(response);
- }
- }
-
- private BeaconDatasetAlleleResponse addInfo(BeaconDatasetAlleleResponse datasetResponse) {
- datasetResponse.setCallCount(1l);
- datasetResponse.setFrequency(0.221);
- datasetResponse.setVariantCount(1l);
- datasetResponse.setSampleCount(1l);
- datasetResponse.setExternalUrl("www.google.com");
- datasetResponse.setNote("This is a sample beacon only");
- Map info = new HashMap<>();
- info.put("note", "Sample Beacon only");
- datasetResponse.setInfo(info);
- return datasetResponse;
- }
-
- private Beacon createSampleBeacon() {
- Beacon beacon = new Beacon();
- beacon.setApiVersion(API_VERSION);
- beacon.setVersion(API_VERSION);
- beacon.setDescription("This is the description for a sample beacon");
- beacon.setName("Sample Beacon");
- beacon.setAlternativeUrl("www.google.ca");
- beacon.setWelcomeUrl("www.url");
- beacon.setDatasets(Arrays.asList(createSampleBeaconDataset()));
- beacon.setCreateDateTime(new Date().toString());
- beacon.setUpdateDateTime(new Date().toString());
- beacon.setSampleAlleleRequests(Arrays.asList(createSampleRequest()));
- beacon.setOrganization(createSampleOrganization());
- beacon.setId(BEACON_ID);
- Map info = new HashMap<>();
- info.put("note", "Sample Beacon only");
- beacon.setInfo(info);
-
- return beacon;
- }
-
- private BeaconAlleleRequest createSampleRequest() {
- BeaconAlleleRequest request = new BeaconAlleleRequest();
- request.setDatasetIds(Arrays.asList(DATASET_ID));
- request.setReferenceName("1");
- request.setAssemblyId("GRCh37");
- request.setIncludeDatasetResponses(true);
- request.setStart(1000l);
- request.setReferenceBases("A");
- request.setAlternateBases("C");
- return request;
-
- }
-
- private BeaconOrganization createSampleOrganization() {
- BeaconOrganization organization = new BeaconOrganization();
- organization.setAddress("123 Nullpointer Ave, StackTrace, Ohio");
- organization.setContactUrl("www.google.com");
- organization.setDescription("Sample implementation of a beacon organization");
- organization.setWelcomeUrl("www.google.com");
- organization.setLogoUrl("www.logoUrl.com");
- organization.setName("Sample Org");
- organization.setId(ORG_ID);
- Map info = new HashMap<>();
- info.put("note", "Sample Beacon only");
- organization.setInfo(info);
-
- return organization;
- }
-
- private BeaconDataset createSampleBeaconDataset() {
- BeaconDataset dataset = new BeaconDataset();
- dataset.setName("Sample Dataset");
- dataset.setAssemblyId("GRCh37");
- dataset.setUpdateDateTime(new Date().toString());
- dataset.setCreateDateTime(new Date().toString());
- dataset.setId(DATASET_ID);
- dataset.setVersion(API_VERSION);
- dataset.setCallCount(10l);
- dataset.setSampleCount(10l);
- dataset.setDescription("Sample implementation");
- Map info = new HashMap<>();
- info.put("note", "Sample Beacon only");
- dataset.setInfo(info);
-
- return dataset;
-
- }
-
- @PostConstruct
- public void init() {
- initAdapter(null);
- }
-
- @Override
- public void initAdapter(AdapterConfig adapterConfig) {
- dataStore = new SampleDataStore();
- }
-
- @Override
- public BeaconAlleleResponse getBeaconAlleleResponse(BeaconAlleleRequest request) throws BeaconException {
-
- BeaconAlleleResponse response = new BeaconAlleleResponse();
- response.setBeaconId(BEACON_ID);
- response.setAlleleRequest(request);
-
- List responses = new ArrayList<>();
- for (String datasetId : request.getDatasetIds()) {
- responses.add(lookupDataset(datasetId,
- request.getAssemblyId(),
- request.getReferenceName(),
- request.getStart(),
- request.getReferenceBases(),
- request.getAlternateBases()));
- }
-
- if (!request.getIncludeDatasetResponses() && responses.size() == 1 && responses.get(0).getError() != null) {
- response.setExists(null);
- response.setError(responses.get(0).getError());
- } else if (request.getIncludeDatasetResponses()) {
- response.setDatasetAlleleResponses(responses);
- }
- boolean exists = false;
- for (BeaconDatasetAlleleResponse datasetResponses : responses) {
-
- if (datasetResponses.getExists()) {
- exists = true;
- }
- }
- response.setExists(exists);
- return response;
- }
-
- @Override
- public BeaconAlleleResponse getBeaconAlleleResponse(String referenceName, Long start, String referenceBases, String alternateBases, String assemblyId, List datasetIds, Boolean includeDatasetResponses) throws BeaconException {
- BeaconAlleleRequest request = new BeaconAlleleRequest();
- request.setReferenceName(referenceName);
- request.setStart(start);
- request.setReferenceBases(referenceBases);
- request.setAlternateBases(alternateBases);
- request.setAssemblyId(assemblyId);
- request.setDatasetIds(datasetIds);
- if (includeDatasetResponses == null){
- includeDatasetResponses = false;
- }
- request.setIncludeDatasetResponses(includeDatasetResponses);
-
- return getBeaconAlleleResponse(request);
- }
-
- @Override
- public Beacon getBeacon() throws BeaconException {
- return createSampleBeacon();
- }
-
-}
diff --git a/sample-beacon-adapter/src/main/java/com/dnastack/beacon/core/adapter/impl/SampleDataStore.java b/sample-beacon-adapter/src/main/java/com/dnastack/beacon/core/adapter/impl/SampleDataStore.java
deleted file mode 100644
index c7d2a83..0000000
--- a/sample-beacon-adapter/src/main/java/com/dnastack/beacon/core/adapter/impl/SampleDataStore.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * The MIT License
- *
- * Copyright 2014 Miroslav Cupak (mirocupak@gmail.com).
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-package com.dnastack.beacon.core.adapter.impl;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * This class simply is acting as a datastorage for the BeaconAdapter to perform lookups on
- *
- * @author patmagee
- */
-public class SampleDataStore {
-
- private final Map DATA;
-
- public SampleDataStore() {
- DATA = new HashMap<>();
- Map assemblies = new HashMap<>();
- Map references = new HashMap<>();
- Map positions = new HashMap<>();
- Map bases = new HashMap<>();
- bases.put("referenceBases", "A");
- bases.put("alternateBases", "C");
- positions.put(1000l, bases);
- references.put("1", positions);
- assemblies.put("GRCh37", references);
- DATA.put(SampleBeaconAdapterImpl.DATASET_ID, assemblies);
-
- }
-
- public Map getDATA() {
- return DATA;
- }
-
-}