Skip to content

Commit

Permalink
Merge pull request #8 from p2m2/develop
Browse files Browse the repository at this point in the history
1.0.2 with new json format
  • Loading branch information
ofilangi authored Nov 15, 2023
2 parents e50cd87 + bfce653 commit d68f3d0
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 112 deletions.
32 changes: 8 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,14 @@ API Service to parse the formats of the metabolomics data acquisition devices of

## API

| Path | Description | Return values | Return values |
|:-----------------------------------------------|:--------------------------------------------------------------------------------|:---------------------------------------------------------|:------------------------------------------------|
| /p2m2tools/api/format/sniffer | returns the file type | `gcms, openlabcds, masslynx-txt, masslynx-xml, xcalibur` | { format : `value`} |
| /p2m2tools/api/format/parse | parse a file from a metabolomics analysis by guessing its format | compound | [ { `GenerricP2M2HeaderFile` : `value` } {} ] |
| /p2m2tools/api/format/parse/gcms | parse a GCMS metabolomics analysis file | compound list | |
| /p2m2tools/api/format/parse/gcms/generic | parse a GCMS metabolomics analysis file. Convert to Generic format P2M2 | header, format, class, compound list | [ { `GenerricP2M2HeaderFile` : `value` } {} ] |
| /p2m2tools/api/format/parse/openlabcds | parse a openlab CDS metabolomics analysis file | compound list | |
| /p2m2tools/api/format/parse/openlabcds/generic | parse a openlab CDS metabolomics analysis file. Convert to Generic format P2M2 | header, format, class, compound list | [ { `GenerricP2M2HeaderFile` : `value` } {} ] |
| /p2m2tools/api/format/parse/masslynx | parse a MassLynx metabolomics analysis file (Quantitative Summary File) | compound list | |
| /p2m2tools/api/format/parse/masslynx/generic | parse a MassLynx metabolomics analysis file. Convert to Generic format P2M2 | header, format, class, compound list | [ { `GenerricP2M2HeaderFile` : `value` } {} ] |
| /p2m2tools/api/format/parse/xcalibur | parse a Xcalibur metabolomics analysis file | compound list | |
| /p2m2tools/api/format/parse/xcalibur/generic | parse a Xcalibur metabolomics analysis file. Convert to Generic format P2M2 | header, format, class, compound list | [ { `GenerricP2M2HeaderFile` : `value` } {} ] |


To see the possible values of GenerricP2M2HeaderFile :
- sample
- metabolite
- retTime
- area
- height
- injectedVolume
- vial
- acquisitionDate
- exportDate
| Path | Description | Return values | Return values |
|:-----------------------------------------------|:-------------------------------------------------------------------------------|:---------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------|
| /p2m2tools/api/format/sniffer | returns the file type | `gcms, openlabcds, masslynx-txt, masslynx-xml, xcalibur` | { format : `value`} |
| /p2m2tools/api/format/parse | parse a file from a metabolomics analysis by guessing its format | compound | `{ header : [sample, metabolite, retTime, area, height, injectedVolume, vial, acquisitionDate, exportDate], samples : list< list<string> > }` |
| /p2m2tools/api/format/parse/gcms | parse a GCMS metabolomics analysis file | compound list | `{ "class":"GCMS","format":"gcms","origin": "","header": <map> ,"results":<list<map>>, "request":{"size:":<int>} }` |
| /p2m2tools/api/format/parse/openlabcds | parse a openlab CDS metabolomics analysis file | compound list | `{ "class":"OpenLabCDS","format":"openlabcds","origin": "","header": <map> ,"results":<list<map>>, "request":{"size:":<int>} }` |
| /p2m2tools/api/format/parse/masslynx | parse a MassLynx metabolomics analysis file (Quantitative Summary File) | compound list | |
| /p2m2tools/api/format/parse/xcalibur | parse a Xcalibur metabolomics analysis file | compound list | |

## prerequisites

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package fr.inrae.metabolomics.p2m2.api

import cask.decorators.compress
import cask.main.Main
import io.undertow.Undertow
import io.undertow.server.handlers.BlockingHandler
import fr.inrae.metabolomics.p2m2.format.XMLQuantitativeDataProcessingMassLynx
import fr.inrae.metabolomics.p2m2.format.ms.{GCMS, GenericP2M2, MassSpectrometryResultSet, OpenLabCDS, QuantifyCompoundSummaryReportMassLynx, QuantifySampleSummaryReportMassLynx, QuantifySummaryReportMassLynx, Xcalibur}
import fr.inrae.metabolomics.p2m2.parser.{GCMSParser, OpenLabCDSParser, ParserManager, ParserUtils, QuantifySummaryReportMassLynxParser, QuantitativeDataProcessingMassLynxParser, XcaliburXlsParser}
import fr.inrae.metabolomics.p2m2.format.ms.{GCMS, GenericP2M2, OpenLabCDS, QuantifyCompoundSummaryReportMassLynx, QuantifySampleSummaryReportMassLynx, QuantifySummaryReportMassLynx, Xcalibur}
import fr.inrae.metabolomics.p2m2.parser.{GCMSParser, OpenLabCDSParser, ParserManager, ParserUtils, QuantifySummaryReportMassLynxParser, XcaliburXlsParser}
import org.slf4j.LoggerFactory
import upickle.default._

Expand Down Expand Up @@ -44,8 +42,8 @@ object APIMetabolomicsFormat extends cask.MainRoutes {
logger.info(s" == start service ${this.getClass.getSimpleName} == ")
@volatile var keepRunning = true

Runtime.getRuntime().addShutdownHook(new Thread {
override def run = {
Runtime.getRuntime.addShutdownHook(new Thread {
override def run() = {
println("* catch signal / stop service *")
server.stop()
keepRunning = false
Expand Down Expand Up @@ -91,7 +89,13 @@ object APIMetabolomicsFormat extends cask.MainRoutes {
@cask.post("/p2m2tools/api/format/parse")
def parser(request: cask.Request) : ujson.Value = {
ParserManager.buildMassSpectrometryObject(request.bytes) match {
case Some(obj) => SeqMapValuesToJson(obj.toGenericP2M2.samples)
case Some(obj) =>
val header = GenericP2M2.HeaderField.values.toList.sorted
val samples = obj.toGenericP2M2.samples
ujson.Obj(
"header" -> header.map(_.toString),
"samples" -> samples.map( sample => header.map( h => sample.getOrElse(h,"")))
)
case None => ujson.Obj()
}
}
Expand All @@ -106,20 +110,12 @@ object APIMetabolomicsFormat extends cask.MainRoutes {
"format" -> "gcms",
"origin" -> obj.origin,
"header" -> MapValuesToJson(obj.header),
"msQuantitativeResults" -> SeqMapValuesToJson(obj.msQuantitativeResults),
"results" -> SeqMapValuesToJson(obj.msQuantitativeResults),
"request" -> ujson.Obj("size:"->request.bytes.length)
)
case Failure(e) =>
System.err.println(e.toString);
cask.Abort(401);ujson.Obj("error" -> e.toString)
}
}

@cask.post("/p2m2tools/api/format/parse/gcms/generic")
def gcmsToGenericP2M2(request: cask.Request): ujson.Value = {
Try(GCMSParser.parseByteArray(request.bytes)) match {
case Success(obj: MassSpectrometryResultSet) => SeqMapValuesToJson(obj.toGenericP2M2.samples)
case Failure(e) => System.err.println(e.toString); cask.Abort(401); ujson.Obj("error" -> e.toString)
System.err.println(e.getMessage)
cask.Abort(401);ujson.Obj("error" -> e.getMessage)
}
}

Expand All @@ -140,19 +136,10 @@ object APIMetabolomicsFormat extends cask.MainRoutes {
"results" -> SeqMapValuesToJson(obj.results),
"request" -> ujson.Obj("size:"->request.bytes.length)
)
case Failure(e) => System.err.println(e.toString); cask.Abort(401); ujson.Obj("error" -> e.toString)
}
}

@cask.post("/p2m2tools/api/format/parse/openlabcds/generic")
def openlabcdsToGenericP2M2(request: cask.Request) : ujson.Value = {
Try(OpenLabCDSParser.parseByteArray(request.bytes)) match {
case Success(obj: MassSpectrometryResultSet) => SeqMapValuesToJson(obj.toGenericP2M2.samples)
case Failure(e) => System.err.println(e.toString); cask.Abort(401); ujson.Obj("error" -> e.toString)
case Failure(e) => System.err.println(e.getMessage); cask.Abort(401); ujson.Obj("error" -> e.getMessage)
}
}


/**
* Get Generic format of Metabolomics File MassLynx format
*
Expand Down Expand Up @@ -183,27 +170,18 @@ object APIMetabolomicsFormat extends cask.MainRoutes {
case Success(obj) => ujson.Obj( "error" -> obj.toString )
case Failure(e) =>
cask.Abort(401);
ujson.Obj("error" -> e.toString)
ujson.Obj("error" -> e.getMessage)
}
}

@cask.post("/p2m2tools/api/format/parse/masslynx/generic")
def masslynxTxtToGenericP2M2(request: cask.Request): ujson.Value = {
Try(QuantifySummaryReportMassLynxParser.parseByteArray(request.bytes)) match {
case Success(obj: MassSpectrometryResultSet) => SeqMapValuesToJson(obj.toGenericP2M2.samples)
case Failure(e) =>
cask.Abort(401);
ujson.Obj("error" -> e.toString)
}
}
/*
@cask.post("/p2m2tools/api/format/parse/masslynx/xml")
def masslynxXml(request: cask.Request): ujson.Value = {
Try(QuantitativeDataProcessingMassLynxParser.parseByteArray(request.bytes)) match {
case Success(obj: XMLQuantitativeDataProcessingMassLynx) => SeqMapValuesToJson(obj.toGenericP2M2)
case Failure(e) =>
cask.Abort(401);
ujson.Obj("error" -> e.toString)
ujson.Obj("error" -> e.getMessage)
}
}
*/
Expand All @@ -227,15 +205,7 @@ object APIMetabolomicsFormat extends cask.MainRoutes {
)),
"request" -> ujson.Obj("size:"->request.bytes.length)
)
case Failure(e) => System.err.println(e.toString); cask.Abort(401); ujson.Obj("error" -> e.toString)
}
}

@cask.post("/p2m2tools/api/format/parse/xcalibur/generic")
def xcaliburToGenericP2M2(request: cask.Request): ujson.Value = {
Try(XcaliburXlsParser.parseByteArray(request.bytes)) match {
case Success(obj: MassSpectrometryResultSet) => SeqMapValuesToJson(obj.toGenericP2M2.samples)
case Failure(e) => System.err.println(e.toString); cask.Abort(401); ujson.Obj("error" -> e.toString)
case Failure(e) => System.err.println(e.getMessage); cask.Abort(401); ujson.Obj("error" -> e.getMessage)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ import cask.router.EndpointMetadata
import cask.router.Decorator
import cask.model.Response
import cask.router.Result

import io.undertow.Undertow
import io.undertow.server.HttpServerExchange
import io.undertow.server.handlers.BlockingHandler
import io.undertow.util.Headers
import io.undertow.util.HttpString

import java.util
import java.util.concurrent.TimeUnit

import scala.concurrent.duration._
import scala.io.StdIn
import scala.jdk.CollectionConverters._
Expand All @@ -29,8 +28,8 @@ object CorsHandler {

val origin = "*"
val accepted = "true"
val headers = Set("Authorization", "Content-Type", "X-Requested-With").asJava
val methods = Set("POST", "GET", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS").asJava
val headers: util.Set[String] = Set("Authorization", "Content-Type", "X-Requested-With").asJava
val methods: util.Set[String] = Set("POST", "GET", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS").asJava
}

case class CorsHandler(dispatchTrie: DispatchTrie[Map[String, (Routes, EndpointMetadata[_])]],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,11 @@ object APIMetabolomicsFormatTest extends TestSuite {
assert(ujson.read(response.text()).asInstanceOf[ujson.Obj].value("format") == ujson.Str("gcms"))
}


test("gcms/generic") - withServer(APIMetabolomicsFormat){
host =>
val response = requests.post(s"$host/p2m2tools/api/format/parse/gcms/generic",data=MetabolomicsData.gcms)
assert(response.statusCode == 200)
assert(ujson.read(response.text()).arr.length == 1)
}

test("gcms generic parsing") - withServer(APIMetabolomicsFormat) {
host =>
val response = requests.post(s"$host/p2m2tools/api/format/parse", data = MetabolomicsData.gcms)
assert(response.statusCode == 200)
assert(ujson.read(response.text()).arr.length == 1)
assert(ujson.read(response.text()).isInstanceOf[ujson.Obj])
}

test("openlabcds") - withServer(APIMetabolomicsFormat) {
Expand All @@ -84,18 +76,12 @@ object APIMetabolomicsFormatTest extends TestSuite {
assert(ujson.read(response.text()).asInstanceOf[ujson.Obj].value("format") == ujson.Str("openlabcds"))
}

test("openlabcds/generic") - withServer(APIMetabolomicsFormat) {
host =>
val response = requests.post(s"$host/p2m2tools/api/format/parse/openlabcds/generic", data = MetabolomicsData.openlabcds)
assert(response.statusCode == 200)
assert(ujson.read(response.text()).arr.length == 4)
}

test("openlabcds generic parsing") - withServer(APIMetabolomicsFormat) {
host =>
val response = requests.post(s"$host/p2m2tools/api/format/parse", data = MetabolomicsData.openlabcds)
assert(response.statusCode == 200)
assert(ujson.read(response.text()).arr.length == 4)
assert(ujson.read(response.text()).isInstanceOf[ujson.Obj])
assert(ujson.read(response.text()).asInstanceOf[ujson.Obj].value("samples").arr.length == 4)
}

test("masslynx") - withServer(APIMetabolomicsFormat) {
Expand All @@ -109,18 +95,12 @@ object APIMetabolomicsFormatTest extends TestSuite {
assert(ujson.read(response.text()).asInstanceOf[ujson.Obj].value("format") == ujson.Str("masslynx"))
}

test("masslynx/generic") - withServer(APIMetabolomicsFormat) {
host =>
val response = requests.post(s"$host/p2m2tools/api/format/parse/masslynx/generic", data = MetabolomicsData.masslynx)
assert(response.statusCode == 200)
assert(ujson.read(response.text()).arr.length == 8313)
}

test("masslynx generic parsing") - withServer(APIMetabolomicsFormat) {
host =>
val response = requests.post(s"$host/p2m2tools/api/format/parse", data = MetabolomicsData.masslynx)
assert(response.statusCode == 200)
assert(ujson.read(response.text()).arr.length == 8313)
assert(ujson.read(response.text()).isInstanceOf[ujson.Obj])
assert(ujson.read(response.text()).asInstanceOf[ujson.Obj].value("samples").arr.length == 8313)
}

test("xcalibur") - withServer(APIMetabolomicsFormat) {
Expand All @@ -133,18 +113,12 @@ object APIMetabolomicsFormatTest extends TestSuite {
assert(ujson.read(response.text()).asInstanceOf[ujson.Obj].value("format") == ujson.Str("xcalibur"))
}

test("xcalibur/generic") - withServer(APIMetabolomicsFormat) {
host =>
val response = requests.post(s"$host/p2m2tools/api/format/parse/xcalibur/generic", data = MetabolomicsData.xcalibur)
assert(response.statusCode == 200)
assert(ujson.read(response.text()).arr.length == 468)
}

test("xcalibur generic parsing") - withServer(APIMetabolomicsFormat) {
host =>
val response = requests.post(s"$host/p2m2tools/api/format/parse", data = MetabolomicsData.xcalibur)
assert(response.statusCode == 200)
assert(ujson.read(response.text()).arr.length == 468)
assert(ujson.read(response.text()).isInstanceOf[ujson.Obj])
assert(ujson.read(response.text()).asInstanceOf[ujson.Obj].value("samples").arr.length == 468)
}

test("Empty close connexion")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package fr.inrae.metabolomics.p2m2.api

import java.nio.file.{Files, Paths}
import scala.io.Source

object MetabolomicsData {
val gcms =
val gcms: String =
"""
|[Header]
|Data File Name C:\Users\ydellero\Desktop\Projets CR\P2M2\TQD\210510_13C_Younes\13CPROT2.qgd
Expand All @@ -15,7 +14,7 @@ object MetabolomicsData {
|ID# Name Type ISTD Group# Mass Ret.Time Start Time End Time A/H Area Height Conc. Mode Peak# Std.Ret.Time Calibration Curve 3rd 2nd 1st Constant Ref.Ion Area Ref.Ion Height Ref.Ion Set Ratio Ref.Ion Ratio Recovery SI Ref.Ion1 m/z Ref.Ion1 Area Ref.Ion1 Height Ref.Ion1 Set Ratio Ref.Ion1 Ratio Ref.Ion2 m/z Ref.Ion2 Area Ref.Ion2 Height Ref.Ion2 Set Ratio Ref.Ion2 Ratio Ref.Ion3 m/z Ref.Ion3 Area Ref.Ion3 Height Ref.Ion3 Set Ratio Ref.Ion3 Ratio Ref.Ion4 m/z Ref.Ion4 Area Ref.Ion4 Height Ref.Ion4 Set Ratio Ref.Ion4 Ratio Ref.Ion5 m/z Ref.Ion5 Area Ref.Ion5 Height Ref.Ion5 Set Ratio Ref.Ion5 Ratio Ret. Index S/N Unit Description Threshold
|1 Glyoxylate (1MEOX) (1TMS )m0 Target 1 160.00 6.405 6.393 6.423 1.080 14 13 0.00029 Auto 3 6.400 Default 0 0 0 0 0 0 84.50 0.00 0.00 18 73.00 0 0 84.50 0.00 59.00 142 129 49.59 1014.29 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1218 4.87 mg/L 0.00000
|""".stripMargin
val openlabcds =
val openlabcds: String =
"""
|Data File C:\Chemstation\1\Data\211011_Corentin-Younes 2021-10-11 15-56-48\Std 500.D
|Sample Name: Std 500
Expand Down

0 comments on commit d68f3d0

Please sign in to comment.