All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lucuma.itc.legacy.LocalItc.scala Maven / Gradle / Ivy

// Copyright (c) 2016-2023 Association of Universities for Research in Astronomy, Inc. (AURA)
// For license information see LICENSE or https://opensource.org/licenses/BSD-3-Clause

package lucuma.itc.legacy

import cats.syntax.all.*
import io.circe.parser.decode
import lucuma.itc.legacy
import lucuma.itc.legacy.given

import java.lang.reflect.Method

/**
 * This class contains methods to call to methods in ItcCalculation via reflection. This is done
 * because the itc-server runs on scala 3 while the ItcCalculation method is based on scala 2
 *
 * Doing the call via reflection with a custom class loader lets us have both scala versions in the
 * jvm at the same time.
 *
 * Note that params are passed as a String for the same reason avoiding conflicts across classes
 * that may not be compatible. Instead we pass back and forth json encoded version of the params
 * essentially the same as if ITC were a server accepting json and responding json
 */
case class LocalItc(classLoader: ClassLoader):
  // We need to keep a single reference to the reflected method
  private val calculateGraphsMethod: Method = classLoader
    .loadClass("edu.gemini.itc.web.servlets.ItcCalculation")
    .getMethod("calculateCharts", classOf[String])

  private val calculateExposureTimeMethod = classLoader
    .loadClass("edu.gemini.itc.web.servlets.ItcCalculation")
    .getMethod("calculateExposureTime", classOf[String])

  private val LegacyRight    = """Right\((.*)\)""".r
  private val LegacyLeft     = """Left\(([\s\S]*?)\)""".r
  private val LegacyLeftList = """Left\(List\(([\s\S]*?)\)\)""".r

  /**
   * This method does a call to the method ItcCalculation.calculation via reflection. This is done
   * because the itc-server runs on scala 3 while the ItcCalculation method is based on scala 2
   *
   * Doing the call via reflection with a custom class loader lets us have both scala versions
   * playing in harmony.
   *
   * Note that the param is passed as a String for the same reason avoiding conflicts across classes
   * that may not be compatible. Instead we pass back and forth json encoded version of the params
   * essentially the same as if ITC were a server accepting json and responding json
   */
  def calculateGraphs(jsonParams: String): Either[List[String], GraphsRemoteResult] =
    val res = calculateGraphsMethod
      .invoke(null, jsonParams) // null as it is a static method
      .asInstanceOf[String]

    res match
      case LegacyRight(result)          =>
        decode[legacy.GraphsRemoteResult](result).leftMap { e =>
          List(e.getMessage())
        }
      case LegacyLeft(result)           =>
        Left(List(result))
      case LegacyLeft(result1, result2) =>
        Left(List(result1, result2))
      case m                            =>
        Left(List(m))

  /**
   * This method does a call to the method ItcCalculation.calculate via reflection.
   */
  def calculateExposureTime(jsonParams: String): Either[List[String], ExposureTimeRemoteResult] =
    val res = calculateExposureTimeMethod
      .invoke(null, jsonParams) // null as it is a static method
      .asInstanceOf[String]

    res match
      case LegacyRight(result)    =>
        decode[legacy.ExposureTimeRemoteResult](result).leftMap { e =>
          List(e.getMessage())
        }
      case LegacyLeft(result)     =>
        Left(result.split("\n").toList)
      case LegacyLeftList(result) =>
        Left(result.split("\n").toList)
      case m                      =>
        Left(List(m))




© 2015 - 2024 Weber Informatics LLC | Privacy Policy