diff --git a/assessment-api/assessment-actors/src/main/scala/org/sunbird/actors/ItemSetActor.scala b/assessment-api/assessment-actors/src/main/scala/org/sunbird/actors/ItemSetActor.scala index 8640dca58..7968bbfa6 100644 --- a/assessment-api/assessment-actors/src/main/scala/org/sunbird/actors/ItemSetActor.scala +++ b/assessment-api/assessment-actors/src/main/scala/org/sunbird/actors/ItemSetActor.scala @@ -86,7 +86,7 @@ class ItemSetActor @Inject() (implicit oec: OntologyEngineContext) extends Abstr ResponseHandler.OK.put("identifier", node.getIdentifier) })) futureList - }).flatMap(f => f).map(f => f.get(1)) + }).flatten.map(f => f.get(1)) } def retire(request: Request): Future[Response] = { diff --git a/assessment-api/assessment-actors/src/main/scala/org/sunbird/managers/CopyManager.scala b/assessment-api/assessment-actors/src/main/scala/org/sunbird/managers/CopyManager.scala index 058a4db58..525b964de 100644 --- a/assessment-api/assessment-actors/src/main/scala/org/sunbird/managers/CopyManager.scala +++ b/assessment-api/assessment-actors/src/main/scala/org/sunbird/managers/CopyManager.scala @@ -52,7 +52,7 @@ object CopyManager { response.put(AssessmentConstants.VERSION_KEY, copiedNode.getMetadata.get(AssessmentConstants.VERSION_KEY)) response }) - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } def validateExistingNode(request: Request, node: Node) = { @@ -81,8 +81,8 @@ object CopyManager { case AssessmentConstants.COPY_TYPE_SHALLOW => updateShallowHierarchy(request, node, originNode, originHierarchy) case _ => updateHierarchy(request, node, originNode, originHierarchy, copyType) } - }).flatMap(f => f) - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } @@ -91,8 +91,8 @@ object CopyManager { copyCreateReq.map(req => { DataNode.create(req).map(copiedNode => { Future(copiedNode) - }).flatMap(f => f) - }).flatMap(f => f) + }).flatten + }).flatten } def updateHierarchy(request: Request, node: Node, originNode: Node, originHierarchy: util.Map[String, AnyRef], copyType: String)(implicit ec: ExecutionContext, oec: OntologyEngineContext): Future[Node] = { @@ -121,8 +121,8 @@ object CopyManager { } }) } else Future(node) - }).flatMap(f => f) - }).flatMap(f => f) + }).flatten + }).flatten } def prepareHierarchyRequest(originHierarchy: util.Map[String, AnyRef], originNode: Node, node: Node, copyType: String, request: Request)(implicit ec: ExecutionContext, oec: OntologyEngineContext): Future[util.Map[String, AnyRef]] = { diff --git a/assessment-api/assessment-actors/src/main/scala/org/sunbird/v5/actors/QuestionActor.scala b/assessment-api/assessment-actors/src/main/scala/org/sunbird/v5/actors/QuestionActor.scala index 10b9dbc6e..3d4320f97 100644 --- a/assessment-api/assessment-actors/src/main/scala/org/sunbird/v5/actors/QuestionActor.scala +++ b/assessment-api/assessment-actors/src/main/scala/org/sunbird/v5/actors/QuestionActor.scala @@ -17,8 +17,7 @@ import org.sunbird.v5.managers.AssessmentV5Manager import java.util import javax.inject.Inject -import scala.collection.JavaConverters -import scala.collection.JavaConverters._ +import scala.jdk.CollectionConverters._ import scala.concurrent.{ExecutionContext, Future} class QuestionActor @Inject()(implicit oec: OntologyEngineContext) extends AbstractActor { @@ -46,7 +45,7 @@ class QuestionActor @Inject()(implicit oec: OntologyEngineContext) extends Abstr } def read(request: Request)(implicit oec: OntologyEngineContext, ec: ExecutionContext): Future[Response] = { - val fields: util.List[String] = JavaConverters.seqAsJavaListConverter(request.get("fields").asInstanceOf[String].split(",").filter(field => StringUtils.isNotBlank(field) && !StringUtils.equalsIgnoreCase(field, "null"))).asJava + val fields: util.List[String] = request.get("fields").asInstanceOf[String].split(",").filter(field => StringUtils.isNotBlank(field) && !StringUtils.equalsIgnoreCase(field, "null")).toList.asJava val extPropNameList:util.List[String] = DefinitionNode.getExternalProps(request.getContext.get("graph_id").asInstanceOf[String], request.getContext.get("version").asInstanceOf[String], request.getContext.get("schemaName").asInstanceOf[String]).asJava request.getRequest.put("fields", extPropNameList) DataNode.read(request).map(node => { @@ -72,12 +71,12 @@ class QuestionActor @Inject()(implicit oec: OntologyEngineContext) extends Abstr DataNode.update(request).map(node => { ResponseHandler.OK.putAll(Map("identifier" -> node.getIdentifier.replace(".img", ""), "versionKey" -> node.getMetadata.get("versionKey")).asJava) }) - }).flatMap(f => f) + }).flatten } def listQuestions(request: Request): Future[Response] = { RequestUtil.validateListRequest(request) - val fields: util.List[String] = JavaConverters.seqAsJavaListConverter(request.get("fields").asInstanceOf[String].split(",").filter(field => StringUtils.isNotBlank(field) && !StringUtils.equalsIgnoreCase(field, "null"))).asJava + val fields: util.List[String] = request.get("fields").asInstanceOf[String].split(",").filter(field => StringUtils.isNotBlank(field) && !StringUtils.equalsIgnoreCase(field, "null")).toList.asJava request.getRequest.put("fields", fields) DataNode.search(request).map(nodeList => { val questionList = nodeList.map(node => AssessmentV5Manager.getQuestionMetadata(node, fields, List().asJava)).asJava @@ -86,7 +85,7 @@ class QuestionActor @Inject()(implicit oec: OntologyEngineContext) extends Abstr } def privateRead(request: Request)(implicit oec: OntologyEngineContext, ec: ExecutionContext): Future[Response] = { - val fields: util.List[String] = JavaConverters.seqAsJavaListConverter(request.get("fields").asInstanceOf[String].split(",").filter(field => StringUtils.isNotBlank(field) && !StringUtils.equalsIgnoreCase(field, "null"))).asJava + val fields: util.List[String] = request.get("fields").asInstanceOf[String].split(",").filter(field => StringUtils.isNotBlank(field) && !StringUtils.equalsIgnoreCase(field, "null")).toList.asJava val extPropNameList:util.List[String] = DefinitionNode.getExternalProps(request.getContext.get("graph_id").asInstanceOf[String], request.getContext.get("version").asInstanceOf[String], request.getContext.get("schemaName").asInstanceOf[String]).asJava request.getRequest.put("fields", extPropNameList) if (StringUtils.isBlank(request.getRequest.getOrDefault("channel", "").asInstanceOf[String])) @@ -118,7 +117,7 @@ class QuestionActor @Inject()(implicit oec: OntologyEngineContext) extends Abstr DataNode.update(updateRequest).map(node => { ResponseHandler.OK.putAll(Map("identifier" -> node.getIdentifier.replace(".img", ""), "versionKey" -> node.getMetadata.get("versionKey")).asJava) }) - }).flatMap(f => f) + }).flatten } def reject(request: Request): Future[Response] = { diff --git a/assessment-api/assessment-actors/src/main/scala/org/sunbird/v5/actors/QuestionSetActor.scala b/assessment-api/assessment-actors/src/main/scala/org/sunbird/v5/actors/QuestionSetActor.scala index bf9ec56a6..4324fd35f 100644 --- a/assessment-api/assessment-actors/src/main/scala/org/sunbird/v5/actors/QuestionSetActor.scala +++ b/assessment-api/assessment-actors/src/main/scala/org/sunbird/v5/actors/QuestionSetActor.scala @@ -21,8 +21,7 @@ import org.sunbird.v5.managers.AssessmentV5Manager import java.util import javax.inject.Inject -import scala.collection.JavaConverters -import scala.collection.JavaConverters._ +import scala.jdk.CollectionConverters._ import scala.concurrent.{ExecutionContext, Future} class QuestionSetActor @Inject()(implicit oec: OntologyEngineContext) extends AbstractActor { @@ -54,7 +53,7 @@ class QuestionSetActor @Inject()(implicit oec: OntologyEngineContext) extends Ab } def read(request: Request)(implicit oec: OntologyEngineContext, ec: ExecutionContext): Future[Response] = { - val fields: util.List[String] = JavaConverters.seqAsJavaListConverter(request.get("fields").asInstanceOf[String].split(",").filter(field => StringUtils.isNotBlank(field) && !StringUtils.equalsIgnoreCase(field, "null"))).asJava + val fields: util.List[String] = request.get("fields").asInstanceOf[String].split(",").filter(field => StringUtils.isNotBlank(field) && !StringUtils.equalsIgnoreCase(field, "null")).toList.asJava request.getRequest.put("fields", fields) DataNode.read(request).map(node => { if (StringUtils.equalsIgnoreCase(node.getMetadata.get("visibility").asInstanceOf[String], "Private")) @@ -64,7 +63,7 @@ class QuestionSetActor @Inject()(implicit oec: OntologyEngineContext) extends Ab } def privateRead(request: Request)(implicit oec: OntologyEngineContext, ec: ExecutionContext): Future[Response] = { - val fields: util.List[String] = JavaConverters.seqAsJavaListConverter(request.get("fields").asInstanceOf[String].split(",").filter(field => StringUtils.isNotBlank(field) && !StringUtils.equalsIgnoreCase(field, "null"))).asJava + val fields: util.List[String] = request.get("fields").asInstanceOf[String].split(",").filter(field => StringUtils.isNotBlank(field) && !StringUtils.equalsIgnoreCase(field, "null")).toList.asJava request.getRequest.put("fields", fields) if (StringUtils.isBlank(request.getRequest.getOrDefault("channel", "").asInstanceOf[String])) throw new ClientException("ERR_INVALID_CHANNEL", "Please Provide Channel!") DataNode.read(request).map(node => { @@ -119,7 +118,7 @@ class QuestionSetActor @Inject()(implicit oec: OntologyEngineContext) extends Ab val date = DateUtils.formatCurrentDate updateReq.putAll(Map("identifiers" -> nodeIds, "metadata" -> Map("status" -> "Review", "prevStatus" -> node.getMetadata.get("status"), "lastStatusChangedOn" -> date, "lastUpdatedOn" -> date).asJava).asJava) updateHierarchyNodes(updateReq, node, Map("status" -> "Review", "hierarchy" -> updatedHierarchy), nodeIds) - }).flatMap(f => f) + }).flatten } def reject(request: Request): Future[Response] = { @@ -195,7 +194,7 @@ class QuestionSetActor @Inject()(implicit oec: OntologyEngineContext) extends Ab DataNode.update(request).map(node => { ResponseHandler.OK.putAll(Map("identifier" -> node.getIdentifier.replace(".img", ""), "versionKey" -> node.getMetadata.get("versionKey")).asJava) }) - }).flatMap(f => f) + }).flatten } def importQuestionSet(request: Request): Future[Response] = importMgr.importObject(request) diff --git a/assessment-api/qs-hierarchy-manager/src/main/scala/org/sunbird/managers/HierarchyManager.scala b/assessment-api/qs-hierarchy-manager/src/main/scala/org/sunbird/managers/HierarchyManager.scala index d14563f92..fec50e02d 100644 --- a/assessment-api/qs-hierarchy-manager/src/main/scala/org/sunbird/managers/HierarchyManager.scala +++ b/assessment-api/qs-hierarchy-manager/src/main/scala/org/sunbird/managers/HierarchyManager.scala @@ -74,12 +74,12 @@ object HierarchyManager { throw new ClientException("ERR_OBJECT_VALIDATION", s"Children with identifier ${filteredChildNodes.map(node => node.getIdentifier.replace(".img", "")).asJava} can't be added because they don't have data in QuML ${rootNodeQumlVer} format.") } updateHierarchyData(unitId, hierarchy, leafNodes, rootNode, request, "add").map(node => ResponseHandler.OK.put("rootId", node.getIdentifier.replaceAll(imgSuffix, ""))) - }).flatMap(f => f) + }).flatten } - }).flatMap(f => f) + }).flatten } } - }).flatMap(f => f) recoverWith {case e: CompletionException => throw e.getCause} + }).flatten recoverWith {case e: CompletionException => throw e.getCause} } @throws[Exception] @@ -104,10 +104,10 @@ object HierarchyManager { if(hierarchy.isEmpty){ Future{ResponseHandler.ERROR(ResponseCode.SERVER_ERROR, ResponseCode.SERVER_ERROR.name(), "hierarchy is empty")} } else updateHierarchyData(unitId, hierarchy, null, rootNode, request, "remove").map(node => ResponseHandler.OK.put("rootId", node.getIdentifier.replaceAll(imgSuffix, ""))) - }).flatMap(f => f) + }).flatten } } - }).flatMap(f => f) recoverWith {case e: CompletionException => throw e.getCause} + }).flatten recoverWith {case e: CompletionException => throw e.getCause} } def attachLeafToRootNode(request: Request, rootNode: Node, operation: String)(implicit oec: OntologyEngineContext, ec: ExecutionContext): Future[Response] = { @@ -149,10 +149,10 @@ object HierarchyManager { .put("children", request.get("children")) } else response }) - }).flatMap(f => f) - }).flatMap(f => f) + }).flatten + }).flatten } - }).flatMap(f => f) + }).flatten } def updateRootHierarchy(hierarchy: java.util.Map[String, AnyRef], leafNodes: List[Node], rootNode: Node, request: Request, operation: String)(implicit oec: OntologyEngineContext, ec: ExecutionContext) = { @@ -212,8 +212,8 @@ object HierarchyManager { ResponseHandler.OK.put("questionSet", metadata) } }) - }).flatMap(f => f) - }).flatMap(f => f) recoverWith { case e: ResourceNotFoundException => { + }).flatten + }).flatten recoverWith { case e: ResourceNotFoundException => { val searchResponse = searchRootIdInElasticSearch(request.get("rootId").asInstanceOf[String]) searchResponse.map(rootHierarchy => { if(!rootHierarchy.isEmpty && StringUtils.isNotEmpty(rootHierarchy.asInstanceOf[util.HashMap[String, AnyRef]].get("identifier").asInstanceOf[String])){ @@ -230,11 +230,11 @@ object HierarchyManager { }) } else Future(ResponseHandler.ERROR(ResponseCode.RESOURCE_NOT_FOUND, ResponseCode.RESOURCE_NOT_FOUND.name(), "rootId " + request.get("rootId") + " does not exist")) - }).flatMap(f => f) + }).flatten } else { Future(ResponseHandler.ERROR(ResponseCode.RESOURCE_NOT_FOUND, ResponseCode.RESOURCE_NOT_FOUND.name(), "rootId " + request.get("rootId") + " does not exist")) } - }).flatMap(f => f) + }).flatten } } } @@ -511,7 +511,7 @@ object HierarchyManager { Future(Map[String, AnyRef]()) else throw new ServerException("ERR_WHILE_FETCHING_HIERARCHY_FROM_CASSANDRA", "Error while fetching hierarchy from cassandra") - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } def getCassandraHierarchy(request: Request)(implicit ec: ExecutionContext, oec: OntologyEngineContext): Future[util.Map[String, AnyRef]] = { @@ -557,9 +557,9 @@ object HierarchyManager { } else { Future(new util.HashMap[String, AnyRef]()) } - }).flatMap(f => f) + }).flatten } - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } def searchRootIdInElasticSearch(rootId: String)(implicit ec: ExecutionContext): Future[util.Map[String, AnyRef]] = { @@ -683,7 +683,7 @@ object HierarchyManager { val updatedMap = leafNodeMap ++ imageLeafNodeMap updatedMap.asJava }) - }).flatMap(f => f) + }).flatten } else { Future{new util.HashMap[String, AnyRef]()} } diff --git a/assessment-api/qs-hierarchy-manager/src/main/scala/org/sunbird/managers/UpdateHierarchyManager.scala b/assessment-api/qs-hierarchy-manager/src/main/scala/org/sunbird/managers/UpdateHierarchyManager.scala index ee6ff1428..7ea85b9e3 100644 --- a/assessment-api/qs-hierarchy-manager/src/main/scala/org/sunbird/managers/UpdateHierarchyManager.scala +++ b/assessment-api/qs-hierarchy-manager/src/main/scala/org/sunbird/managers/UpdateHierarchyManager.scala @@ -36,7 +36,7 @@ object UpdateHierarchyManager { val existingChildren = existingHierarchy.getOrElse(HierarchyConstants.CHILDREN, new java.util.ArrayList[java.util.HashMap[String, AnyRef]]()).asInstanceOf[java.util.List[java.util.Map[String, AnyRef]]] val nodes = List(node) addChildNodesInNodeList(existingChildren, request, nodes).map(list => (existingHierarchy, list)) - }).flatMap(f => f) + }).flatten .map(result => { val nodes = result._2 TelemetryManager.info("NodeList final size: " + nodes.size) @@ -54,11 +54,11 @@ object UpdateHierarchyManager { if (request.getContext.getOrDefault("shouldImageDelete", false.asInstanceOf[AnyRef]).asInstanceOf[Boolean]) deleteHierarchy(request) Future(response) - }).flatMap(f => f) - }).flatMap(f => f) - }).flatMap(f => f) + }).flatten + }).flatten + }).flatten }) - }).flatMap(f => f).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten.flatten recoverWith { case e: CompletionException => throw e.getCause } } private def validateRequest(request: Request)(implicit ec: ExecutionContext): (java.util.HashMap[String, AnyRef], java.util.HashMap[String, AnyRef]) = { @@ -142,7 +142,7 @@ object UpdateHierarchyManager { }) recover { case e: ResourceNotFoundException => TelemetryManager.log("No hierarchy is present in cassandra for identifier:" + rootNode.getIdentifier) } } } else Future(response.getResult.toMap.getOrElse(HierarchyConstants.HIERARCHY, "").asInstanceOf[String]) - }).flatMap(f => f) + }).flatten } private def addChildNodesInNodeList(childrenMaps: java.util.List[java.util.Map[String, AnyRef]], request: Request, nodes: scala.collection.immutable.List[Node])(implicit oec: OntologyEngineContext, ec: ExecutionContext): Future[scala.collection.immutable.List[Node]] = { @@ -153,7 +153,7 @@ object UpdateHierarchyManager { addChildNodesInNodeList(child.get(HierarchyConstants.CHILDREN).asInstanceOf[java.util.List[java.util.Map[String, AnyRef]]], request, modifiedList) } else Future(modifiedList) - }).flatMap(f => f) + }).flatten }).toList Future.sequence(futures).map(f => f.flatten.distinct) } else { @@ -394,7 +394,7 @@ object UpdateHierarchyManager { put(HierarchyConstants.CHILD_NODES, new java.util.ArrayList[String](childNodeIds)) }) validateNodes(finalEnrichedNodeList, rootId, request).map(result => HierarchyManager.convertNodeToMap(finalEnrichedNodeList)) - }).flatMap(f => f) + }).flatten } else { updateNodeList(nodeList, rootId, new java.util.HashMap[String, AnyRef]() { { @@ -441,7 +441,7 @@ object UpdateHierarchyManager { updateHierarchyRelatedData(request, hierarchyStructure.getOrDefault(id, Map[String, Int]()), node.getMetadata.get(HierarchyConstants.DEPTH).asInstanceOf[Int] + 1, id, nodeList, hierarchyStructure, nxtEnrichedNodeList) } else Future(nxtEnrichedNodeList) - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } }) if (CollectionUtils.isNotEmpty(futures)) { diff --git a/assessment-api/qs-hierarchy-manager/src/test/scala/org/sunbird/managers/UpdateHierarchyManagerTest.scala b/assessment-api/qs-hierarchy-manager/src/test/scala/org/sunbird/managers/UpdateHierarchyManagerTest.scala index 9ff348674..ae8928725 100644 --- a/assessment-api/qs-hierarchy-manager/src/test/scala/org/sunbird/managers/UpdateHierarchyManagerTest.scala +++ b/assessment-api/qs-hierarchy-manager/src/test/scala/org/sunbird/managers/UpdateHierarchyManagerTest.scala @@ -137,7 +137,7 @@ import scala.concurrent.ExecutionContext .one().getString("hierarchy") assert(StringUtils.isNotEmpty(hierarchy)) }) - }).flatMap(f => f) + }).flatten } "updateHierarchy with section without children" should "update the hierarchy structure for questionset" in { @@ -172,7 +172,7 @@ import scala.concurrent.ExecutionContext .one().getString("hierarchy") assert(StringUtils.isNotEmpty(hierarchy)) }) - }).flatMap(f => f) + }).flatten } }*/ diff --git a/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/manager/CollectionCSVManager.scala b/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/manager/CollectionCSVManager.scala index 26c106d70..f79ad56a2 100644 --- a/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/manager/CollectionCSVManager.scala +++ b/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/manager/CollectionCSVManager.scala @@ -93,6 +93,7 @@ object CollectionCSVManager extends CollectionInputFileReader { val maxAllowedContentSize = Platform.getInteger(CollectionTOCConstants.SUNBIRD_TOC_MAX_FIRST_LEVEL_UNITS,30) val csvFile: File = new File(collectionTocFileName) + var fos: FileOutputStream = null var out: OutputStreamWriter = null var csvPrinter: CSVPrinter = null try{ @@ -100,7 +101,11 @@ object CollectionCSVManager extends CollectionInputFileReader { TelemetryManager.info("CollectionCSVManager:createFileAndStore -> Creating file for CSV at Location: " + csvFile.getAbsolutePath) touch(csvFile) - out = new OutputStreamWriter(new FileOutputStream(csvFile), StandardCharsets.UTF_8) + // Assign FileOutputStream to its own variable before passing it to + // OutputStreamWriter so the finally block can close fos independently + // if the OutputStreamWriter constructor throws. + fos = new FileOutputStream(csvFile) + out = new OutputStreamWriter(fos, StandardCharsets.UTF_8) out.write(ByteOrderMark.UTF_BOM) val csvFormat = CSVFormat.DEFAULT.withFirstRecordAsHeader().withRecordSeparator(System.lineSeparator()).withQuoteMode(QuoteMode.NON_NUMERIC) @@ -176,6 +181,9 @@ object CollectionCSVManager extends CollectionInputFileReader { try { if (csvPrinter != null) csvPrinter.close() if (out != null) out.close() + // Close fos explicitly in case OutputStreamWriter construction failed + // and out was never assigned (in which case fos would otherwise leak). + if (fos != null) fos.close() if (null != csvFile && csvFile.exists) deleteQuietly(csvFile.getCanonicalFile) } catch { case e: IOException => diff --git a/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/util/CollectionTOCUtil.scala b/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/util/CollectionTOCUtil.scala index cdb5eccda..cae5a2f00 100644 --- a/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/util/CollectionTOCUtil.scala +++ b/content-api/collection-csv-actors/src/main/scala/org.sunbird/collectioncsv/util/CollectionTOCUtil.scala @@ -55,7 +55,7 @@ object CollectionTOCUtil { returnDIALCodes.asScala.toList.map(rec => rec.asScala.toMap[String,AnyRef]).map(_.getOrElse(CollectionTOCConstants.IDENTIFIER, "")).asInstanceOf[List[String]] } catch { - case e:Exception => println("CollectionTOCUtil: validateDIALCodes --> exception: " + e.getMessage) + case e:Exception => TelemetryManager.error("CollectionTOCUtil: validateDIALCodes --> exception: " + e.getMessage, e) List.empty } } diff --git a/content-api/content-actors/src/main/scala/org/sunbird/channel/managers/ChannelManager.scala b/content-api/content-actors/src/main/scala/org/sunbird/channel/managers/ChannelManager.scala index 463df64b7..015fdbe6e 100644 --- a/content-api/content-actors/src/main/scala/org/sunbird/channel/managers/ChannelManager.scala +++ b/content-api/content-actors/src/main/scala/org/sunbird/channel/managers/ChannelManager.scala @@ -12,6 +12,7 @@ import com.mashape.unirest.http.Unirest import org.apache.commons.collections4.CollectionUtils import org.apache.commons.lang3.StringUtils import org.sunbird.common.JsonUtils +import org.sunbird.telemetry.logger.TelemetryManager import scala.jdk.CollectionConverters._ import scala.collection.mutable.ListBuffer @@ -32,7 +33,7 @@ object ChannelManager { } def getAllFrameworkList(): util.List[util.Map[String, AnyRef]] = { - val url: String = Platform.getString("composite.search.url", "https://dev.sunbirded.org/action/composite/v3/search") + val url: String = Platform.getString(ChannelConstants.COMPOSITE_SEARCH_URL_CONFIG_KEY, ChannelConstants.COMPOSITE_SEARCH_URL_DEFAULT) val httpResponse: HttpResponse[String] = Unirest.post(url).header("Content-Type", "application/json").body("""{"request":{"filters":{"objectType":"Framework","status":"Live"},"fields":["name","code","objectType","identifier"]}}""").asString if (200 != httpResponse.getStatus) throw new ServerException("ERR_FETCHING_FRAMEWORK", "Error while fetching framework.") @@ -104,13 +105,13 @@ object ChannelManager { } catch { case e: Exception => // Log error and continue without populating categories - System.out.println("Error fetching primary/additional categories: " + e.getMessage) + TelemetryManager.error("Error fetching primary/additional categories: " + e.getMessage, e) } } def getAdditionalCategories()(implicit httpUtil: HttpUtil): java.util.List[String] = { val body = """{"request":{"filters":{"objectType":"ObjectCategory","visibility":["Default"]},"fields":["name","identifier"]}}""" - val url: String = Platform.getString("composite.search.url", "https://dev.sunbirded.org/action/composite/v3/search") + val url: String = Platform.getString(ChannelConstants.COMPOSITE_SEARCH_URL_CONFIG_KEY, ChannelConstants.COMPOSITE_SEARCH_URL_DEFAULT) val httpResponse = httpUtil.post(url, body) if (200 != httpResponse.status) throw new ServerException("ERR_FETCHING_OBJECT_CATEGORY", "Error while fetching object categories for additional category list.") val response: Response = JsonUtils.deserialize(httpResponse.body, classOf[Response]) @@ -138,7 +139,7 @@ object ChannelManager { } private def getPrimaryCategories(body: String)(implicit httpUtil: HttpUtil): java.util.List[java.util.Map[String, AnyRef]] = { - val url: String = Platform.getString("composite.search.url", "https://dev.sunbirded.org/action/composite/v3/search") + val url: String = Platform.getString(ChannelConstants.COMPOSITE_SEARCH_URL_CONFIG_KEY, ChannelConstants.COMPOSITE_SEARCH_URL_DEFAULT) val httpResponse = httpUtil.post(url, body) if (200 != httpResponse.status) throw new ServerException("ERR_FETCHING_OBJECT_CATEGORY_DEFINITION", "Error while fetching primary categories.") val response: Response = JsonUtils.deserialize(httpResponse.body, classOf[Response]) @@ -147,7 +148,7 @@ object ChannelManager { } def getMasterCategoryList(): List[String] = { - val url: String = Platform.getString("composite.search.url", "https://dev.sunbirded.org/action/composite/v3/search") + val url: String = Platform.getString(ChannelConstants.COMPOSITE_SEARCH_URL_CONFIG_KEY, ChannelConstants.COMPOSITE_SEARCH_URL_DEFAULT) val httpResponse: HttpResponse[String] = Unirest.post(url).header("Content-Type", "application/json").body("""{"request":{"filters":{"objectType":"ObjectCategory"},"fields":["name"]}}""").asString if (200 != httpResponse.getStatus) throw new ServerException("ERR_FETCHING_OBJECT_CATEGORY", "Error while fetching object category.") diff --git a/content-api/content-actors/src/main/scala/org/sunbird/content/actors/ContentActor.scala b/content-api/content-actors/src/main/scala/org/sunbird/content/actors/ContentActor.scala index 57dc8bd00..12d1b56e9 100644 --- a/content-api/content-actors/src/main/scala/org/sunbird/content/actors/ContentActor.scala +++ b/content-api/content-actors/src/main/scala/org/sunbird/content/actors/ContentActor.scala @@ -155,7 +155,7 @@ class ContentActor @Inject() (implicit oec: OntologyEngineContext, ss: StorageSe if (null != node & StringUtils.isNotBlank(node.getObjectType)) request.getContext.put(ContentConstants.SCHEMA_NAME, node.getObjectType.toLowerCase()) UploadManager.upload(request, node) - }).flatMap(f => f) + }).flatten } def copy(request: Request): Future[Response] = { @@ -215,7 +215,7 @@ class ContentActor @Inject() (implicit oec: OntologyEngineContext, ss: StorageSe if (StringUtils.equalsAnyIgnoreCase(ContentConstants.PROCESSING, node.getMetadata.getOrDefault(ContentConstants.STATUS, "").asInstanceOf[String])) throw new ClientException("ERR_NODE_ACCESS_DENIED", "Review Operation Can't Be Applied On Node Under Processing State") else ReviewManager.review(request, node) - }).flatMap(f => f) + }).flatten } def publishContent(request: Request): Future[Response] = { @@ -234,7 +234,7 @@ class ContentActor @Inject() (implicit oec: OntologyEngineContext, ss: StorageSe throw new ClientException("ERR_NODE_ACCESS_DENIED", "Publish Operation Can't Be Applied On Node Under Processing State") node.getMetadata.put(ContentConstants.LAST_PUBLISHED_BY, publisher) PublishManager.publish(request, node) - }).flatMap(f => f) + }).flatten } def populateDefaultersForCreation(request: Request): Future[Unit] = { @@ -272,7 +272,7 @@ class ContentActor @Inject() (implicit oec: OntologyEngineContext, ss: StorageSe TelemetryManager.error("Error setting license to Redis: " + e.getMessage, e) } } else { - println("Default License is not available for channel: " + channelId) + TelemetryManager.warn("Default License is not available for channel: " + channelId) } }).recover { case e: Exception => @@ -311,8 +311,8 @@ class ContentActor @Inject() (implicit oec: OntologyEngineContext, ss: StorageSe throw new ClientException("ERR_CONTENT_INVALID_FILE_NAME", "Please Provide Valid File Name.") if (!preSignedObjTypes.contains(`type`)) throw new ClientException("ERR_INVALID_PRESIGNED_URL_TYPE", "Invalid pre-signed url type. It should be one of " + StringUtils.join(preSignedObjTypes, ",")) - if(StringUtils.isNotBlank(filePath) && filePath.size > 100) - throw new ClientException("ERR_CONTENT_INVALID_FILE_PATH", "Please provide valid filepath of character length 100 or Less ") + if(StringUtils.isNotBlank(filePath) && filePath.size > ContentConstants.MAX_FILE_PATH_SIZE) + throw new ClientException("ERR_CONTENT_INVALID_FILE_PATH", "Please provide valid filepath of character length " + ContentConstants.MAX_FILE_PATH_SIZE + " or Less ") } def dataModifier(node: Node): Node = { @@ -385,7 +385,7 @@ class ContentActor @Inject() (implicit oec: OntologyEngineContext, ss: StorageSe val identifier: String = node.getIdentifier.replace(".img", "") ResponseHandler.OK.put("node_id", identifier).put(ContentConstants.IDENTIFIER, identifier) }) - }).flatMap(f => f) + }).flatten } } diff --git a/content-api/content-actors/src/main/scala/org/sunbird/content/dial/DIALConstants.scala b/content-api/content-actors/src/main/scala/org/sunbird/content/dial/DIALConstants.scala index d01212ff2..00c933471 100644 --- a/content-api/content-actors/src/main/scala/org/sunbird/content/dial/DIALConstants.scala +++ b/content-api/content-actors/src/main/scala/org/sunbird/content/dial/DIALConstants.scala @@ -28,4 +28,9 @@ object DIALConstants { val DIAL_EID: String = "BE_QR_IMAGE_GENERATOR" val batchInfo: String = "batchInfo" + // QR code generation defaults + val DEFAULT_ERROR_CORRECTION_LEVEL: String = "H" + val DEFAULT_PIXELS_PER_BLOCK: Int = 2 + val DEFAULT_QR_CODE_MARGIN: Int = 3 + } \ No newline at end of file diff --git a/content-api/content-actors/src/main/scala/org/sunbird/content/dial/DIALManager.scala b/content-api/content-actors/src/main/scala/org/sunbird/content/dial/DIALManager.scala index 101707808..0f8b360d0 100644 --- a/content-api/content-actors/src/main/scala/org/sunbird/content/dial/DIALManager.scala +++ b/content-api/content-actors/src/main/scala/org/sunbird/content/dial/DIALManager.scala @@ -34,9 +34,9 @@ object DIALManager { private val kfClient = new KafkaClient val DIALTOPIC: String = Platform.config.getString("kafka.dial.request.topic") val defaultConfig: Mmap[String, Any] = Mmap( - "errorCorrectionLevel" -> "H", - "pixelsPerBlock" -> 2, - "qrCodeMargin" -> 3, + "errorCorrectionLevel" -> DIALConstants.DEFAULT_ERROR_CORRECTION_LEVEL, + "pixelsPerBlock" -> DIALConstants.DEFAULT_PIXELS_PER_BLOCK, + "qrCodeMargin" -> DIALConstants.DEFAULT_QR_CODE_MARGIN, "textFontName" -> "Verdana", "textFontSize" -> 11, "textCharacterSpacing" -> 0.1, @@ -138,7 +138,7 @@ object DIALManager { }).toList val updatedNodes: Future[List[Node]] = Future.sequence(futureList) getResponse(requestMap, updatedNodes, result) - }).flatMap(f => f) + }).flatten } def linkCollection(objectId: String, requestMap: Map[String, List[String]], reqContext: util.Map[String, AnyRef])(implicit oec: OntologyEngineContext, ec: ExecutionContext): Future[Response] = { @@ -213,7 +213,7 @@ object DIALManager { requestMap.keys.toList.diff(identifiers) } } else throw new ResourceNotFoundException(DIALErrors.ERR_DIALCODE_LINK, DIALErrors.ERR_CONTENT_NOT_FOUND_MSG + requestMap.keySet.asJava) - }).flatMap(f => f) + }).flatten } def getResponse(requestMap: Map[String, List[String]], updatedNodes: Future[List[Node]], invalidIds: List[String])(implicit ec: ExecutionContext): Future[Response] = { diff --git a/content-api/content-actors/src/main/scala/org/sunbird/content/publish/mgr/PublishManager.scala b/content-api/content-actors/src/main/scala/org/sunbird/content/publish/mgr/PublishManager.scala index ba9ddb7fb..1e2884daf 100644 --- a/content-api/content-actors/src/main/scala/org/sunbird/content/publish/mgr/PublishManager.scala +++ b/content-api/content-actors/src/main/scala/org/sunbird/content/publish/mgr/PublishManager.scala @@ -44,7 +44,7 @@ object PublishManager { response.put(ContentConstants.NODE_ID, node.getIdentifier) Future(response) - }).flatMap(f => f) + }).flatten } @throws[Exception] diff --git a/content-api/content-actors/src/main/scala/org/sunbird/content/review/mgr/ReviewManager.scala b/content-api/content-actors/src/main/scala/org/sunbird/content/review/mgr/ReviewManager.scala index fe71574bb..c9426fa23 100644 --- a/content-api/content-actors/src/main/scala/org/sunbird/content/review/mgr/ReviewManager.scala +++ b/content-api/content-actors/src/main/scala/org/sunbird/content/review/mgr/ReviewManager.scala @@ -25,7 +25,7 @@ object ReviewManager { DataNode.update(updateReq).map(node => { ResponseHandler.OK.putAll(Map("identifier" -> node.getIdentifier.replace(".img", ""), "versionKey" -> node.getMetadata.get("versionKey")).asJava) }) - }).flatMap(f => f) + }).flatten } } diff --git a/content-api/content-actors/src/main/scala/org/sunbird/content/upload/mgr/UploadManager.scala b/content-api/content-actors/src/main/scala/org/sunbird/content/upload/mgr/UploadManager.scala index ebb4ef4fb..9a531ce18 100644 --- a/content-api/content-actors/src/main/scala/org/sunbird/content/upload/mgr/UploadManager.scala +++ b/content-api/content-actors/src/main/scala/org/sunbird/content/upload/mgr/UploadManager.scala @@ -45,7 +45,7 @@ object UploadManager { updateNode(request, node.getIdentifier, mediaType, node.getObjectType, result + (ContentConstants.ARTIFACT_BASE_PATH -> filePath.get)) else updateNode(request, node.getIdentifier, mediaType, node.getObjectType, result) - }).flatMap(f => f) + }).flatten } def updateNode(request: Request, identifier: String, mediaType: String, objectType: String, result: Map[String, AnyRef])(implicit oec: OntologyEngineContext, ec: ExecutionContext): Future[Response] = { diff --git a/content-api/content-actors/src/main/scala/org/sunbird/content/util/AcceptFlagManager.scala b/content-api/content-actors/src/main/scala/org/sunbird/content/util/AcceptFlagManager.scala index 4230fed84..ae0029a42 100644 --- a/content-api/content-actors/src/main/scala/org/sunbird/content/util/AcceptFlagManager.scala +++ b/content-api/content-actors/src/main/scala/org/sunbird/content/util/AcceptFlagManager.scala @@ -35,9 +35,9 @@ object AcceptFlagManager { response } }) - }).flatMap(f => f) + }).flatten } - }).flatMap(f => f) + }).flatten } private def createOrUpdateImageNode(request: Request, node: Node)(implicit ec: ExecutionContext, oec: OntologyEngineContext): Future[Node] = { @@ -77,7 +77,7 @@ object AcceptFlagManager { } else { Future(hierarchyResponse) } - }).flatMap(f => f) + }).flatten } else { updateNode(request) } diff --git a/content-api/content-actors/src/main/scala/org/sunbird/content/util/AssetCopyManager.scala b/content-api/content-actors/src/main/scala/org/sunbird/content/util/AssetCopyManager.scala index a0b12cded..e893da4a1 100644 --- a/content-api/content-actors/src/main/scala/org/sunbird/content/util/AssetCopyManager.scala +++ b/content-api/content-actors/src/main/scala/org/sunbird/content/util/AssetCopyManager.scala @@ -34,7 +34,7 @@ object AssetCopyManager { response.put(AssetConstants.VERSION_KEY, copiedNode.getMetadata.get(AssetConstants.VERSION_KEY)) response }) - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } def copyAsset(node: Node, request: Request)(implicit ec: ExecutionContext, oec: OntologyEngineContext, ss: StorageService): Future[Node] = { @@ -42,8 +42,8 @@ object AssetCopyManager { copyCreateReq.map(req => { DataNode.create(req).map(copiedNode => { artifactUpload(node, copiedNode, request) - }).flatMap(f => f) - }).flatMap(f => f) + }).flatten + }).flatten } def getCopyRequest(node: Node, request: Request)(implicit ec: ExecutionContext, oec: OntologyEngineContext): Future[Request] = { diff --git a/content-api/content-actors/src/main/scala/org/sunbird/content/util/ContentConstants.scala b/content-api/content-actors/src/main/scala/org/sunbird/content/util/ContentConstants.scala index 6ddc98881..18d38b110 100644 --- a/content-api/content-actors/src/main/scala/org/sunbird/content/util/ContentConstants.scala +++ b/content-api/content-actors/src/main/scala/org/sunbird/content/util/ContentConstants.scala @@ -79,4 +79,6 @@ object ContentConstants { val RELEASE: String = "release" val DRAFT: String = "Draft" val LIVE: String = "Live" + + val MAX_FILE_PATH_SIZE: Int = 100 } diff --git a/content-api/content-actors/src/main/scala/org/sunbird/content/util/CopyManager.scala b/content-api/content-actors/src/main/scala/org/sunbird/content/util/CopyManager.scala index a34c228d8..24b8b6a7c 100644 --- a/content-api/content-actors/src/main/scala/org/sunbird/content/util/CopyManager.scala +++ b/content-api/content-actors/src/main/scala/org/sunbird/content/util/CopyManager.scala @@ -65,7 +65,7 @@ object CopyManager { response.put(ContentConstants.VERSION_KEY, copiedNode.getMetadata.get(ContentConstants.VERSION_KEY)) response }) - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } def copyContent(node: Node, request: Request)(implicit ec: ExecutionContext, oec: OntologyEngineContext, ss: StorageService): Future[Node] = { @@ -74,8 +74,8 @@ object CopyManager { copyCreateReq.map(req => { DataNode.create(req).map(copiedNode => { artifactUpload(node, copiedNode, request) - }).flatMap(f => f) - }).flatMap(f => f) + }).flatten + }).flatten } def copyCollection(originNode: Node, request: Request)(implicit ec:ExecutionContext, oec: OntologyEngineContext, ss: StorageService):Future[Node] = { @@ -93,7 +93,7 @@ object CopyManager { case _ => updateHierarchy(request,node, originNode, originHierarchy, copyType) } }).flatMap(f=>f) - }).flatMap(f => f) recoverWith {case e: CompletionException => throw e.getCause} + }).flatten recoverWith {case e: CompletionException => throw e.getCause} } def updateHierarchy(request: Request, node: Node, originNode: Node, originHierarchy: util.Map[String, AnyRef], copyType:String)(implicit ec: ExecutionContext, oec: OntologyEngineContext): Future[Node] = { @@ -289,7 +289,7 @@ object CopyManager { } else mimeTypeManager.upload(copiedNode.getIdentifier, copiedNode, node.getMetadata.getOrDefault(ContentConstants.ARTIFACT_URL, "").asInstanceOf[String], None, UploadParams()) uploadFuture.map(uploadData => { DataNode.update(getUpdateRequest(request, copiedNode, uploadData.getOrElse(ContentConstants.ARTIFACT_URL, "").asInstanceOf[String])) - }).flatMap(f => f) + }).flatten } else Future(copiedNode) } diff --git a/content-api/content-actors/src/main/scala/org/sunbird/content/util/DiscardManager.scala b/content-api/content-actors/src/main/scala/org/sunbird/content/util/DiscardManager.scala index b763344bf..944b9ddf1 100644 --- a/content-api/content-actors/src/main/scala/org/sunbird/content/util/DiscardManager.scala +++ b/content-api/content-actors/src/main/scala/org/sunbird/content/util/DiscardManager.scala @@ -57,7 +57,7 @@ object DiscardManager { private def discardForCollection(node: Node, request: Request)(implicit executionContext: ExecutionContext, oec: OntologyEngineContext): Future[java.lang.Boolean] = { request.put(ContentConstants.IDENTIFIERS, if (node.getMetadata.containsKey(ContentConstants.PACKAGE_VERSION)) List(node.getIdentifier) else List(node.getIdentifier, node.getIdentifier + ContentConstants.IMAGE_SUFFIX)) request.getContext.put(ContentConstants.SCHEMA_NAME, ContentConstants.COLLECTION_SCHEMA_NAME) - oec.graphService.deleteExternalProps(request).map(resp => DataNode.deleteNode(request)).flatMap(f => f) + oec.graphService.deleteExternalProps(request).map(resp => DataNode.deleteNode(request)).flatten } diff --git a/content-api/content-actors/src/main/scala/org/sunbird/content/util/FlagManager.scala b/content-api/content-actors/src/main/scala/org/sunbird/content/util/FlagManager.scala index fb479cf10..bb9a5a9df 100644 --- a/content-api/content-actors/src/main/scala/org/sunbird/content/util/FlagManager.scala +++ b/content-api/content-actors/src/main/scala/org/sunbird/content/util/FlagManager.scala @@ -57,7 +57,7 @@ object FlagManager { response.put("versionKey", flaggedNode.getMetadata.get("versionKey")) response }) - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } def updateCollection(request: Request)(implicit oec: OntologyEngineContext, ec: ExecutionContext): Future[Node] = { @@ -75,7 +75,7 @@ object FlagManager { } val updateNode = DataNode.update(request) updateNode - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } private def fetchHierarchy(request: Request)(implicit ec: ExecutionContext, oec: OntologyEngineContext): Future[Any] = { diff --git a/content-api/content-actors/src/main/scala/org/sunbird/util/ChannelConstants.scala b/content-api/content-actors/src/main/scala/org/sunbird/util/ChannelConstants.scala index e49708593..b3ed977a3 100644 --- a/content-api/content-actors/src/main/scala/org/sunbird/util/ChannelConstants.scala +++ b/content-api/content-actors/src/main/scala/org/sunbird/util/ChannelConstants.scala @@ -20,4 +20,7 @@ object ChannelConstants { val categoryKeyList: List[String] = List(CONTENT_PRIMARY_CATEGORIES, COLLECTION_PRIMARY_CATEGORIES, ASSET_PRIMARY_CATEGORIES, CONTENT_ADDITIONAL_CATEGORIES, COLLECTION_ADDITIONAL_CATEGORIES, ASSET_ADDITIONAL_CATEGORIES) + val COMPOSITE_SEARCH_URL_CONFIG_KEY: String = "composite.search.url" + val COMPOSITE_SEARCH_URL_DEFAULT: String = "https://dev.sunbirded.org/action/composite/v3/search" + } diff --git a/content-api/hierarchy-manager/src/main/scala/org/sunbird/managers/HierarchyManager.scala b/content-api/hierarchy-manager/src/main/scala/org/sunbird/managers/HierarchyManager.scala index 853dc76be..de2d3cddc 100644 --- a/content-api/hierarchy-manager/src/main/scala/org/sunbird/managers/HierarchyManager.scala +++ b/content-api/hierarchy-manager/src/main/scala/org/sunbird/managers/HierarchyManager.scala @@ -74,12 +74,12 @@ object HierarchyManager { response } }) - }).flatMap(f => f) - }).flatMap(f => f) + }).flatten + }).flatten } - }).flatMap(f => f) + }).flatten } - }).flatMap(f => f) recoverWith {case e: CompletionException => throw e.getCause} + }).flatten recoverWith {case e: CompletionException => throw e.getCause} } @throws[Exception] @@ -109,11 +109,11 @@ object HierarchyManager { response } }) - }).flatMap(f => f) + }).flatten } - }).flatMap(f => f) + }).flatten } - }).flatMap(f => f) recoverWith {case e: CompletionException => throw e.getCause} + }).flatten recoverWith {case e: CompletionException => throw e.getCause} } @throws[Exception] @@ -172,9 +172,9 @@ object HierarchyManager { ResponseHandler.OK.put("content", metadata) } }) - }).flatMap(f => f) - }).flatMap(f => f) - }).flatMap(f => f) recoverWith { case e: ResourceNotFoundException => + }).flatten + }).flatten + }).flatten recoverWith { case e: ResourceNotFoundException => val searchResponse = searchRootIdInElasticSearch(request.get("rootId").asInstanceOf[String]) searchResponse.map(rootHierarchy => { if(!rootHierarchy.isEmpty && StringUtils.isNotEmpty(rootHierarchy.asInstanceOf[util.HashMap[String, AnyRef]].get("identifier").asInstanceOf[String])){ @@ -199,7 +199,7 @@ object HierarchyManager { } else { Future(ResponseHandler.ERROR(ResponseCode.RESOURCE_NOT_FOUND, ResponseCode.RESOURCE_NOT_FOUND.name(), "rootId " + request.get("rootId") + " does not exist")) } - }).flatMap(f => f) + }).flatten } } @@ -375,7 +375,7 @@ object HierarchyManager { req.put("hierarchy", ScalaJsonUtils.serialize(updatedHierarchy)) req.put("identifier", rootNode.getIdentifier) oec.graphService.saveExternalProps(req) - }).flatMap(f => f).recoverWith { + }).flatten.recoverWith { case clientException: ClientException => if(clientException.getMessage.equalsIgnoreCase("Validation Errors")) { Future(ResponseHandler.ERROR(ResponseCode.CLIENT_ERROR, ResponseCode.CLIENT_ERROR.name(), clientException.getMessages.asScala.mkString(","))) } else throw clientException @@ -450,7 +450,7 @@ object HierarchyManager { Future(Map[String, AnyRef]()) else throw new ServerException("ERR_WHILE_FETCHING_HIERARCHY_FROM_CASSANDRA", "Error while fetching hierarchy from cassandra") - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } @@ -478,9 +478,9 @@ object HierarchyManager { } else Future(Map[String, AnyRef]()) } else Future(Map[String, AnyRef]()) - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } @@ -530,9 +530,9 @@ object HierarchyManager { } else { Future(new util.HashMap[String, AnyRef]()) } - }).flatMap(f => f) + }).flatten } - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } def searchRootIdInElasticSearch(rootId: String)(implicit ec: ExecutionContext): Future[util.Map[String, AnyRef]] = { @@ -671,7 +671,7 @@ object HierarchyManager { val updatedMap = leafNodeMap ++ imageLeafNodeMap updatedMap.asJava }) - }).flatMap(f => f) + }).flatten } else { Future{new util.HashMap[String, AnyRef]()} } diff --git a/content-api/hierarchy-manager/src/main/scala/org/sunbird/managers/UpdateHierarchyManager.scala b/content-api/hierarchy-manager/src/main/scala/org/sunbird/managers/UpdateHierarchyManager.scala index fff8513c5..693104dc7 100644 --- a/content-api/hierarchy-manager/src/main/scala/org/sunbird/managers/UpdateHierarchyManager.scala +++ b/content-api/hierarchy-manager/src/main/scala/org/sunbird/managers/UpdateHierarchyManager.scala @@ -36,7 +36,7 @@ object UpdateHierarchyManager { val existingChildren = existingHierarchy.getOrElse(HierarchyConstants.CHILDREN, new java.util.ArrayList[java.util.HashMap[String, AnyRef]]()).asInstanceOf[java.util.List[java.util.Map[String, AnyRef]]] val nodes = List(node) addChildNodesInNodeList(existingChildren, request, nodes).map(list => (existingHierarchy, list)) - }).flatMap(f => f) + }).flatten .map(result => { val nodes = result._2 @@ -59,16 +59,16 @@ object UpdateHierarchyManager { if (request.getContext.getOrDefault("shouldImageDelete", false.asInstanceOf[AnyRef]).asInstanceOf[Boolean]) deleteHierarchy(request) Future(response) - }).flatMap(f => f) - }).flatMap(f => f).recoverWith { + }).flatten + }).flatten.recoverWith { case clientException: ClientException => if(clientException.getMessage.equalsIgnoreCase("Validation Errors")) { Future(ResponseHandler.ERROR(ResponseCode.CLIENT_ERROR, ResponseCode.CLIENT_ERROR.name(), clientException.getMessages.mkString(","))) } else throw clientException case e: Exception => throw e } - }).flatMap(f => f) + }).flatten }) - }).flatMap(f => f).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten.flatten recoverWith { case e: CompletionException => throw e.getCause } } private def validateRequest(request: Request)(implicit ec: ExecutionContext): Unit = { @@ -149,7 +149,7 @@ object UpdateHierarchyManager { }) recover { case e: ResourceNotFoundException => TelemetryManager.log("No hierarchy is present in cassandra for identifier:" + rootNode.getIdentifier) } } } else Future(response.getResult.toMap.getOrElse(HierarchyConstants.HIERARCHY, "").asInstanceOf[String]) - }).flatMap(f => f) + }).flatten } private def addChildNodesInNodeList(childrenMaps: java.util.List[java.util.Map[String, AnyRef]], request: Request, nodes: scala.collection.immutable.List[Node])(implicit oec: OntologyEngineContext, ec: ExecutionContext): Future[scala.collection.immutable.List[Node]] = { @@ -160,7 +160,7 @@ object UpdateHierarchyManager { addChildNodesInNodeList(child.get(HierarchyConstants.CHILDREN).asInstanceOf[java.util.List[java.util.Map[String, AnyRef]]], request, modifiedList) } else Future(modifiedList) - }).flatMap(f => f) + }).flatten }).toList Future.sequence(futures).map(f => f.flatten.distinct) } else { @@ -363,7 +363,7 @@ object UpdateHierarchyManager { put(HierarchyConstants.CHILD_NODES, new java.util.ArrayList[String](childNodeIds)) }) validateNodes(finalEnrichedNodeList, rootId).map(result => HierarchyManager.convertNodeToMap(finalEnrichedNodeList)) - }).flatMap(f => f) + }).flatten } else { updateNodeList(nodeList, rootId, new java.util.HashMap[String, AnyRef]() { { @@ -418,7 +418,7 @@ object UpdateHierarchyManager { updateHierarchyRelatedData(hierarchyStructure.getOrDefault(id, Map[String, Int]()), node.getMetadata.get(HierarchyConstants.DEPTH).asInstanceOf[Int] + 1, id, nodeList, hierarchyStructure, nxtEnrichedNodeList, request, rootId) } else Future(nxtEnrichedNodeList) - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } }) if (CollectionUtils.isNotEmpty(futures)) { diff --git a/ontology-engine/graph-core_2.13/src/main/scala/org/sunbird/graph/validator/NodeValidator.scala b/ontology-engine/graph-core_2.13/src/main/scala/org/sunbird/graph/validator/NodeValidator.scala index 210068144..843f600ca 100644 --- a/ontology-engine/graph-core_2.13/src/main/scala/org/sunbird/graph/validator/NodeValidator.scala +++ b/ontology-engine/graph-core_2.13/src/main/scala/org/sunbird/graph/validator/NodeValidator.scala @@ -9,6 +9,7 @@ import org.sunbird.graph.common.enums.SystemProperties import org.sunbird.graph.dac.model.{Filter, MetadataCriterion, Node, SearchConditions, SearchCriteria} import org.sunbird.graph.exception.GraphErrorCodes import org.sunbird.graph.service.operation.SearchAsyncOperations +import org.sunbird.telemetry.logger.TelemetryManager import scala.jdk.CollectionConverters._ import scala.collection.convert.ImplicitConversions._ @@ -34,7 +35,7 @@ object NodeValidator { private def getDataNodes(graphId: String, identifiers: util.List[String])(implicit ec: ExecutionContext, oec: OntologyEngineContext) = { if (identifiers.size() == 1) { - System.out.println("NodeValidator: Singular lookup for identifier: " + identifiers.get(0)) + TelemetryManager.log("NodeValidator: Singular lookup for identifier: " + identifiers.get(0)) oec.graphService.getNodeByUniqueId(graphId, identifiers.get(0), false, new org.sunbird.common.dto.Request()) .map(node => util.Arrays.asList(node)) .recover { diff --git a/ontology-engine/graph-dac-api/src/main/java/org/sunbird/graph/dac/model/SearchCriteria.java b/ontology-engine/graph-dac-api/src/main/java/org/sunbird/graph/dac/model/SearchCriteria.java index 84078d161..bd905bfcf 100644 --- a/ontology-engine/graph-dac-api/src/main/java/org/sunbird/graph/dac/model/SearchCriteria.java +++ b/ontology-engine/graph-dac-api/src/main/java/org/sunbird/graph/dac/model/SearchCriteria.java @@ -7,7 +7,6 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -23,8 +22,8 @@ public class SearchCriteria implements Serializable { private boolean countQuery; private int resultSize = 0; private int startPosition = 0; - private List fields = new LinkedList(); - private List sortOrder = new LinkedList(); + private List fields = new ArrayList(); + private List sortOrder = new ArrayList(); Map params = new HashMap(); int pIndex = 1; @@ -237,7 +236,7 @@ public void setSortOrder(List sortOrder) { public void sort(Sort sort) { if (null == sortOrder) - sortOrder = new LinkedList(); + sortOrder = new ArrayList(); sortOrder.add(sort); } diff --git a/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/nodes/DataNode.scala b/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/nodes/DataNode.scala index 6faef8520..a5d3ea25b 100644 --- a/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/nodes/DataNode.scala +++ b/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/nodes/DataNode.scala @@ -34,8 +34,8 @@ object DataNode { saveExternalProperties(node.getIdentifier, node.getExternalData, request.getContext, request.getObjectType), createRelations(request.graphId, node, request.getContext)) futureList.map(list => result) - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause} - }).flatMap(f => f) + }).flatten recoverWith { case e: CompletionException => throw e.getCause} + }).flatten } @throws[Exception] @@ -49,8 +49,8 @@ object DataNode { updateExternalProperties(node.getIdentifier, node.getExternalData, request.getContext, request.getObjectType, request), updateRelations(request.graphId, node, request.getContext)) futureList.map(list => result) - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause} - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause} + }).flatten recoverWith { case e: CompletionException => throw e.getCause} + }).flatten recoverWith { case e: CompletionException => throw e.getCause} } @throws[Exception] @@ -70,7 +70,7 @@ object DataNode { populateExternalProperties(fields, node, request, extPropNameList) else Future(node) - }).flatMap(f => f) recoverWith { + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } @@ -160,7 +160,7 @@ object DataNode { Future { node } - }).flatMap(f => f) + }).flatten } private def updateRelations(graphId: String, node: Node, context: util.Map[String, AnyRef])(implicit ec: ExecutionContext, oec: OntologyEngineContext) : Future[Response] = { @@ -298,7 +298,7 @@ object DataNode { populateExternalProperties(nodeList.asScala.toList, fields, request, extPropNameList) else Future(nodeList.asScala.toList) - }).flatMap(f => f) recoverWith { + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } diff --git a/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/path/DataSubGraph.scala b/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/path/DataSubGraph.scala index 192390e46..dc3d1e0af 100644 --- a/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/path/DataSubGraph.scala +++ b/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/path/DataSubGraph.scala @@ -9,6 +9,7 @@ import org.sunbird.graph.dac.model.{Node, Relation, SubGraph} import org.sunbird.graph.nodes.DataNode import org.sunbird.graph.schema.{DefinitionFactory, DefinitionNode, ObjectCategoryDefinition} import org.sunbird.graph.utils.NodeUtil +import org.sunbird.telemetry.logger.TelemetryManager import scala.jdk.CollectionConverters._ import org.sunbird.graph.utils.NodeUtil.{convertJsonProperties, handleKeyNames} @@ -37,7 +38,6 @@ object DataSubGraph { val dataMap = new util.HashMap[String, AnyRef] val relMap = new util.HashMap[String, AnyRef] readSubGraphData(request, dataMap, relMap).map(sub => { - println("subGraphData out " + sub) sub }) } @@ -60,7 +60,7 @@ object DataSubGraph { }) finalDataMap.asScala.map(entry => { val mapData = entry._2.asInstanceOf[java.util.Map[String, AnyRef]].asScala - println("mapData " + mapData.toString()) + TelemetryManager.log("mapData " + mapData.toString()) val outRelations: util.List[Relation] = mapData.getOrElse("outRelations", new util.ArrayList[Relation]).asInstanceOf[util.List[Relation]] for (rel <- outRelations.asScala) { val subReq = new Request() @@ -71,7 +71,7 @@ object DataSubGraph { subReq.getContext.put("objectType", rel.getEndNodeObjectType) subReq.getContext.put("isRoot", "true") subReq.put("identifier", rel.getEndNodeId) - println("readSubGraphData "+ readSubGraphData(subReq, dataMap, relMap)) + TelemetryManager.log("readSubGraphData " + subReq.get("identifier")) } }) Future{finalDataMap} @@ -107,7 +107,6 @@ object DataSubGraph { finalMetadata.keySet.retainAll(fields) finalMetadata.put("identifier", node.getIdentifier) } - println("definitionMap "+ definitionMap) val relMap: util.Map[String, util.List[util.Map[String, AnyRef]]] = geOutRelationMap(node, updatedMetadataMap, definitionMap) finalMetadata.putAll(relMap) finalMetadata diff --git a/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/DefinitionNode.scala b/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/DefinitionNode.scala index d1e44b538..9b54c24f2 100644 --- a/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/DefinitionNode.scala +++ b/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/DefinitionNode.scala @@ -130,7 +130,7 @@ object DefinitionNode { node }) - }).flatMap(f => f) + }).flatten } def postProcessor(request: Request, node: Node)(implicit ec: ExecutionContext, oec: OntologyEngineContext): Node = { diff --git a/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/FrameworkValidator.scala b/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/FrameworkValidator.scala index 0d4a73bff..a325a6afe 100644 --- a/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/FrameworkValidator.scala +++ b/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/FrameworkValidator.scala @@ -65,8 +65,8 @@ trait FrameworkValidator extends IDefinition { } } super.validate(node, operation) - }).flatMap(f => f) - }).flatMap(f => f) + }).flatten + }).flatten } private def validateAndSetMultiFrameworks(node: Node, orgFwTerms: List[String], targetFwTerms: List[String], masterCategories: List[Map[String, AnyRef]])(implicit ec: ExecutionContext, oec: OntologyEngineContext): Future[Map[String, AnyRef]] = { @@ -88,7 +88,7 @@ trait FrameworkValidator extends IDefinition { } }) getValidatedTerms(node, targetFwTerms) - }).flatMap(f => f) + }).flatten } diff --git a/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/RelationValidator.scala b/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/RelationValidator.scala index be85b003e..822765d06 100644 --- a/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/RelationValidator.scala +++ b/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/RelationValidator.scala @@ -48,7 +48,7 @@ trait RelationValidator extends IDefinition { node }).map(node => { super.validate(node, operation) - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause} + }).flatten recoverWith { case e: CompletionException => throw e.getCause} } else { super.validate(node, operation) } diff --git a/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/VersionKeyValidator.scala b/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/VersionKeyValidator.scala index 7c223d42d..b0abf4c72 100644 --- a/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/VersionKeyValidator.scala +++ b/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/VersionKeyValidator.scala @@ -25,7 +25,7 @@ trait VersionKeyValidator extends IDefinition { isValidVersionkey(node).map(isValid => { if(!isValid)throw new ClientException(ResponseCode.CLIENT_ERROR.name, "Invalid version Key") else super.validate(node, operation) - }).flatMap(f => f) + }).flatten } else { super.validate(node, operation) } diff --git a/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/VersioningNode.scala b/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/VersioningNode.scala index 0e81b68f5..4ae9d3937 100644 --- a/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/VersioningNode.scala +++ b/ontology-engine/graph-engine_2.13/src/main/scala/org/sunbird/graph/schema/validator/VersioningNode.scala @@ -46,7 +46,7 @@ trait VersioningNode extends IDefinition { getEditableNode(identifier, node) else Future{node} - }).flatMap(f => f) + }).flatten } private def getNodeToRead(identifier: String, mode: String, disableCache: Option[Boolean])(implicit oec: OntologyEngineContext, ec: ExecutionContext): Future[Node] = { @@ -141,7 +141,7 @@ trait VersioningNode extends IDefinition { } else { super.getNode(identifier, "read", null) } - }).flatMap(f => f) + }).flatten } private def nodeCacheAsyncHandler(objKey: String)(implicit oec: OntologyEngineContext, ec: ExecutionContext): Future[String] = { @@ -151,7 +151,7 @@ trait VersioningNode extends IDefinition { val nodeMap = NodeUtil.serialize(node, null, node.getObjectType.toLowerCase().replace("image", ""), getSchemaVersion()) Future(ScalaJsonUtils.serialize(nodeMap)) } else Future("") - }).flatMap(f => f) + }).flatten } private def getSchemaNameFromMimeType(node: Node) : String = { diff --git a/ontology-engine/parseq/src/main/scala/org/sunbird/parseq/Task.scala b/ontology-engine/parseq/src/main/scala/org/sunbird/parseq/Task.scala index c55bd7283..d5e67ddb5 100644 --- a/ontology-engine/parseq/src/main/scala/org/sunbird/parseq/Task.scala +++ b/ontology-engine/parseq/src/main/scala/org/sunbird/parseq/Task.scala @@ -21,7 +21,7 @@ object Task { } yield (List(result1, result2)) result.map(futures => { Future.sequence(futures) - }).flatMap(f => f) + }).flatten } } diff --git a/platform-core/cassandra-connector/src/main/java/org/sunbird/cassandra/CassandraConnector.java b/platform-core/cassandra-connector/src/main/java/org/sunbird/cassandra/CassandraConnector.java index 3918cfc2c..ebbe9e47f 100644 --- a/platform-core/cassandra-connector/src/main/java/org/sunbird/cassandra/CassandraConnector.java +++ b/platform-core/cassandra-connector/src/main/java/org/sunbird/cassandra/CassandraConnector.java @@ -22,6 +22,9 @@ public class CassandraConnector { /** Cassandra Session Map. */ private static Map sessionMap = new HashMap(); + /** Guard to prevent registering duplicate JVM shutdown hooks. */ + private static boolean shutdownHookRegistered = false; + static { if (Platform.getBoolean("service.db.cassandra.enabled", true)) prepareSession("lp", getConsistencyLevel("lp")); @@ -77,9 +80,11 @@ private static void prepareSession(String sessionKey, ConsistencyLevel level) { .build().connect()); } - registerShutdownHook(); + if (!shutdownHookRegistered) { + registerShutdownHook(); + shutdownHookRegistered = true; + } } catch (Exception e) { - e.printStackTrace(); TelemetryManager.error("Error! While Loading Cassandra Properties." + e.getMessage(), e); } } @@ -129,21 +134,33 @@ private static List getSocketAddress(List hosts) { } /** - * Close connection with the cluster. - * + * Close all Cassandra sessions gracefully. + * Each session is closed individually so a failure in one does not + * prevent closing the others. */ public static void close() { - sessionMap.entrySet().stream().forEach(stream -> stream.getValue().close()); + sessionMap.forEach((key, session) -> { + if (session != null && !session.isClosed()) { + try { + session.close(); + } catch (Exception e) { + TelemetryManager.error("Error closing Cassandra session for key: " + key + " — " + e.getMessage(), e); + } + } + }); + sessionMap.clear(); } /** - * Register JVM shutdown hook to close cassandra open session. + * Register a single JVM shutdown hook to close all open Cassandra sessions. + * Protected by shutdownHookRegistered so it is called only once even when + * prepareSession() is invoked multiple times. */ private static void registerShutdownHook() { Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { - TelemetryManager.log("Shutting down Cassandra connector session"); + TelemetryManager.log("Shutting down Cassandra connector — closing all sessions"); CassandraConnector.close(); } }); diff --git a/platform-core/kafka-client/src/main/scala/org/sunbird/kafka/client/KafkaClient.scala b/platform-core/kafka-client/src/main/scala/org/sunbird/kafka/client/KafkaClient.scala index 60f659c57..9432377e6 100644 --- a/platform-core/kafka-client/src/main/scala/org/sunbird/kafka/client/KafkaClient.scala +++ b/platform-core/kafka-client/src/main/scala/org/sunbird/kafka/client/KafkaClient.scala @@ -15,6 +15,8 @@ class KafkaClient { private val producer = createProducer() private val consumer = createConsumer() + registerShutdownHook() + protected def getProducer: Producer[Long, String] = producer protected def getConsumer: Consumer[Long, String] = consumer @@ -35,6 +37,33 @@ class KafkaClient { topics.keySet.contains(topic) } + /** + * Closes the Kafka producer and consumer, flushing any pending messages first. + * Safe to call multiple times. + */ + def close(): Unit = { + try { + if (producer != null) { + producer.flush() + producer.close() + } + } catch { + case e: Exception => TelemetryManager.error("Error closing KafkaProducer: " + e.getMessage, e) + } + try { + if (consumer != null) consumer.close() + } catch { + case e: Exception => TelemetryManager.error("Error closing KafkaConsumer: " + e.getMessage, e) + } + } + + private def registerShutdownHook(): Unit = { + Runtime.getRuntime.addShutdownHook(new Thread(() => { + TelemetryManager.log("Shutting down KafkaClient — closing producer and consumer") + close() + })) + } + private def createProducer(): KafkaProducer[Long, String] = { new KafkaProducer[Long, String](new Properties() { { diff --git a/platform-core/platform-cache/src/main/scala/org/sunbird/cache/util/RedisConnector.scala b/platform-core/platform-cache/src/main/scala/org/sunbird/cache/util/RedisConnector.scala index 9300ab1b7..be15363e6 100644 --- a/platform-core/platform-cache/src/main/scala/org/sunbird/cache/util/RedisConnector.scala +++ b/platform-core/platform-cache/src/main/scala/org/sunbird/cache/util/RedisConnector.scala @@ -1,6 +1,7 @@ package org.sunbird.cache.util import org.sunbird.common.Platform +import org.sunbird.telemetry.logger.TelemetryManager import redis.clients.jedis.{Jedis, JedisPool, JedisPoolConfig} /** @@ -14,6 +15,8 @@ trait RedisConnector { private val INDEX = Platform.getInteger("redis.dbIndex", 0) private val jedisPool: JedisPool = new JedisPool(getConfig(), HOST, PORT) + registerShutdownHook() + /** * This Method Returns a connection object from connection pool. * @@ -28,21 +31,45 @@ trait RedisConnector { } /** - * This Method takes a connection object and put it back to pool. + * This Method takes a connection object and returns it to pool. + * Uses jedis.close() which is the modern, non-deprecated approach + * and correctly returns the connection to the pool (or closes it if broken). * * @param jedis */ protected def returnConnection(jedis: Jedis): Unit = { - try if (null != jedis) jedisPool.returnResource(jedis) - catch { - case e: Exception => throw e + if (null != jedis) { + try jedis.close() + catch { + case e: Exception => TelemetryManager.error("Error returning Redis connection to pool: " + e.getMessage, e) + } + } + } + + /** + * Closes the JedisPool, releasing all connections. + * Called automatically via the JVM shutdown hook. + */ + def closePool(): Unit = { + if (jedisPool != null && !jedisPool.isClosed) { + try jedisPool.close() + catch { + case e: Exception => TelemetryManager.error("Error closing JedisPool: " + e.getMessage, e) + } } } + private def registerShutdownHook(): Unit = { + Runtime.getRuntime.addShutdownHook(new Thread(() => { + TelemetryManager.log("Shutting down RedisConnector — closing connection pool") + closePool() + })) + } + private def getConfig(): JedisPoolConfig = { val config: JedisPoolConfig = new JedisPoolConfig() config.setMaxTotal(MAX_CONNECTIONS) - config.setBlockWhenExhausted(true); + config.setBlockWhenExhausted(true) config } } diff --git a/platform-modules/mimetype-manager/src/main/scala/org/sunbird/cloudstore/StorageService.scala b/platform-modules/mimetype-manager/src/main/scala/org/sunbird/cloudstore/StorageService.scala index 840b3a6d6..b58dbc871 100644 --- a/platform-modules/mimetype-manager/src/main/scala/org/sunbird/cloudstore/StorageService.scala +++ b/platform-modules/mimetype-manager/src/main/scala/org/sunbird/cloudstore/StorageService.scala @@ -4,6 +4,7 @@ import org.apache.tika.Tika import org.sunbird.cloud.storage.IStorageService import org.sunbird.common.{Platform, Slug} import org.sunbird.common.exception.ServerException +import org.sunbird.telemetry.logger.TelemetryManager import java.io.File import javax.inject.{Inject, Singleton} @@ -94,9 +95,9 @@ class StorageService @Inject()(storageService: IStorageService) { try { getService.getUri(getContainerName, key, false) } catch { - case e: Exception => - println("StorageService --> getUri --> Exception: " + e.getMessage) - "" + case e:Exception => + TelemetryManager.error("StorageService --> getUri --> Exception: " + e.getMessage, e) + "" } def getMimeType(fileName: String): String = new Tika().detect(fileName) diff --git a/platform-modules/mimetype-manager/src/main/scala/org/sunbird/mimetype/mgr/impl/CollectionMimeTypeMgrImpl.scala b/platform-modules/mimetype-manager/src/main/scala/org/sunbird/mimetype/mgr/impl/CollectionMimeTypeMgrImpl.scala index d05b1554a..dedd39b90 100644 --- a/platform-modules/mimetype-manager/src/main/scala/org/sunbird/mimetype/mgr/impl/CollectionMimeTypeMgrImpl.scala +++ b/platform-modules/mimetype-manager/src/main/scala/org/sunbird/mimetype/mgr/impl/CollectionMimeTypeMgrImpl.scala @@ -61,7 +61,7 @@ class CollectionMimeTypeMgrImpl(implicit ss: StorageService) extends BaseMimeTyp }) else Future{List(true)} - }).flatMap(f => f) + }).flatten } def getCollectionHierarchy(request: Request, rootNode: Node)(implicit ec: ExecutionContext, oec: OntologyEngineContext): Future[Any] = { diff --git a/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/CategoryActor.scala b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/CategoryActor.scala index 87dd9f8a1..ab8c8ac74 100644 --- a/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/CategoryActor.scala +++ b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/CategoryActor.scala @@ -12,7 +12,7 @@ import org.sunbird.graph.OntologyEngineContext import org.sunbird.graph.nodes.DataNode import org.sunbird.utils.Constants import org.sunbird.utils.taxonomy.RequestUtil -import org.sunbird.mangers.FrameworkManager +import org.sunbird.managers.FrameworkManager import org.sunbird.cache.impl.RedisCache import scala.concurrent.{ExecutionContext, Future} diff --git a/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/CategoryInstanceActor.scala b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/CategoryInstanceActor.scala index ed49ea02a..52347f68b 100644 --- a/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/CategoryInstanceActor.scala +++ b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/CategoryInstanceActor.scala @@ -3,16 +3,14 @@ package org.sunbird.actors import org.apache.commons.lang3.StringUtils import org.sunbird.actor.core.BaseActor -import org.sunbird.common.Slug import org.sunbird.common.dto.{Request, Response, ResponseHandler} import org.sunbird.common.exception.ClientException import org.sunbird.graph.OntologyEngineContext -import org.sunbird.graph.dac.enums.RelationTypes import org.sunbird.graph.dac.model.Node import org.sunbird.graph.nodes.DataNode import org.sunbird.graph.utils.NodeUtil import org.sunbird.utils.Constants -import org.sunbird.utils.taxonomy.RequestUtil +import org.sunbird.utils.taxonomy.{RequestUtil, TaxonomyUtil} import java.util import scala.jdk.CollectionConverters._ @@ -50,28 +48,20 @@ class CategoryInstanceActor @Inject()(implicit oec: OntologyEngineContext) exten DataNode.read(getFrameworkReq).map(node => { if (null != node && StringUtils.equalsAnyIgnoreCase(node.getIdentifier, frameworkId)) { validateCategoryObject(request).map(catNode => { - request.getRequest.put(Constants.IDENTIFIER, generateIdentifier(frameworkId, catNode.getIdentifier)) + request.getRequest.put(Constants.IDENTIFIER, TaxonomyUtil.generateIdentifier(frameworkId, catNode.getIdentifier)) val frameworkList = new util.ArrayList[Map[String, AnyRef]] val relationMap = new util.HashMap[String, AnyRef] relationMap.put("identifier", frameworkId) - relationMap.put("index", getCategoryIndex(node)) + relationMap.put("index", TaxonomyUtil.getNextSequenceIndex(node)) frameworkList.add(relationMap) request.put("frameworks", frameworkList) DataNode.create(request).map(node => { ResponseHandler.OK.put(Constants.IDENTIFIER, node.getIdentifier) .put(Constants.VERSION_KEY, node.getMetadata.get("versionKey")) }) - }).flatMap(f => f) + }).flatten } else throw new ClientException("ERR_INVALID_FRAMEWORK_ID", s"Invalid FrameworkId: '${frameworkId}' for Categoryinstance ") - }).flatMap(f => f) - } - - private def getCategoryIndex(node: Node): Integer = { - val indexList = (node.getOutRelations.asScala ++ node.getInRelations.asScala).filter(r => (StringUtils.equals(r.getRelationType,RelationTypes.SEQUENCE_MEMBERSHIP.relationName()) && StringUtils.equals(r.getStartNodeId, node.getIdentifier))) - .map(relation => { - relation.getMetadata.getOrDefault("IL_SEQUENCE_INDEX",1.asInstanceOf[Number]).asInstanceOf[Number].intValue() - }) - if (indexList.nonEmpty) indexList.max + 1 else 1 + }).flatten } private def read(request: Request): Future[Response] = { @@ -85,7 +75,7 @@ class CategoryInstanceActor @Inject()(implicit oec: OntologyEngineContext) exten val categoryId = request.getContext.getOrDefault(Constants.CATEGORY, "").asInstanceOf[String]; RequestUtil.restrictProperties(request) validateCategoryInstanceObject(request) - request.getContext.put(Constants.IDENTIFIER, generateIdentifier(request.getRequest.getOrDefault(Constants.FRAMEWORK, "").asInstanceOf[String], categoryId)) + request.getContext.put(Constants.IDENTIFIER, TaxonomyUtil.generateIdentifier(request.getRequest.getOrDefault(Constants.FRAMEWORK, "").asInstanceOf[String], categoryId)) DataNode.update(request).map(node => { ResponseHandler.OK.put(Constants.IDENTIFIER, node.getIdentifier).put(Constants.VERSION_KEY, node.getMetadata.get("versionKey")) }) @@ -93,7 +83,7 @@ class CategoryInstanceActor @Inject()(implicit oec: OntologyEngineContext) exten private def retire(request: Request): Future[Response] = { validateCategoryInstanceObject(request) - request.getContext.put(Constants.IDENTIFIER, generateIdentifier(request.getRequest.getOrDefault(Constants.FRAMEWORK, "").asInstanceOf[String], request.getRequest.getOrDefault(Constants.CATEGORY, "").asInstanceOf[String])) + request.getContext.put(Constants.IDENTIFIER, TaxonomyUtil.generateIdentifier(request.getRequest.getOrDefault(Constants.FRAMEWORK, "").asInstanceOf[String], request.getRequest.getOrDefault(Constants.CATEGORY, "").asInstanceOf[String])) request.getRequest.put("status", "Retired") DataNode.update(request).map(node => { ResponseHandler.OK.put(Constants.IDENTIFIER, node.getIdentifier).put(Constants.VERSION_KEY, node.getMetadata.get("versionKey")) @@ -105,7 +95,7 @@ class CategoryInstanceActor @Inject()(implicit oec: OntologyEngineContext) exten val categoryId = request.getRequest.getOrDefault(Constants.CATEGORY, "").asInstanceOf[String] if (frameworkId.isEmpty()) throw new ClientException("ERR_INVALID_FRAMEWORK_ID", s"Invalid FrameworkId: '${frameworkId}' for CategoryInstance ") if (categoryId.isEmpty()) throw new ClientException("ERR_INVALID_CATEGORY_ID", s"Invalid CategoryId: '${categoryId}' for categoryInstance") - val categoryInstanceId = generateIdentifier(frameworkId, categoryId) + val categoryInstanceId = TaxonomyUtil.generateIdentifier(frameworkId, categoryId) val getCategoryReq = new Request() getCategoryReq.setContext(new util.HashMap[String, AnyRef]() { { @@ -140,10 +130,4 @@ class CategoryInstanceActor @Inject()(implicit oec: OntologyEngineContext) exten })(ec) } - private def generateIdentifier(scopeId: String, code: String): String = { - var id: String = null - if (StringUtils.isNotBlank(scopeId)) id = Slug.makeSlug(scopeId + "_" + code) - id - } - } \ No newline at end of file diff --git a/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/FrameworkActor.scala b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/FrameworkActor.scala index d53a116b0..10929bbf7 100644 --- a/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/FrameworkActor.scala +++ b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/FrameworkActor.scala @@ -11,7 +11,7 @@ import org.sunbird.graph.dac.model.{Node, SubGraph} import org.sunbird.graph.nodes.DataNode import org.sunbird.graph.path.DataSubGraph import org.sunbird.graph.utils.{NodeUtil, ScalaJsonUtils} -import org.sunbird.mangers.FrameworkManager +import org.sunbird.managers.FrameworkManager import org.sunbird.utils.{CategoryCache, FrameworkCache} import org.sunbird.utils.Constants import org.sunbird.utils.taxonomy.RequestUtil @@ -61,7 +61,7 @@ class FrameworkActor @Inject()(implicit oec: OntologyEngineContext) extends Base ResponseHandler.OK.put(Constants.NODE_ID, frameNode.getIdentifier).put("versionKey", frameNode.getMetadata.get("versionKey")) }) } else throw new ClientException("ERR_INVALID_CHANNEL_ID", "Please provide valid channel identifier") - }).flatMap(f => f) + }).flatten } else throw new ClientException("ERR_INVALID_REQUEST", "Invalid Request. Please Provide Required Properties!") } @@ -100,7 +100,7 @@ class FrameworkActor @Inject()(implicit oec: OntologyEngineContext) extends Base ResponseHandler.OK.put(Constants.FRAMEWORK, javaMap) } } - }).flatMap(f => f) + }).flatten } } else throw new ClientException("ERR_INVALID_REQUEST", "Invalid Request. Please Provide Required Properties!") } @@ -166,7 +166,7 @@ class FrameworkActor @Inject()(implicit oec: OntologyEngineContext) extends Base }) } else throw new ClientException("ERR_INVALID_FRAMEWORK_ID", "Please provide valid framework identifier") } else throw new ClientException("ERR_INVALID_CHANNEL_ID", "Please provide valid channel identifier") - }).flatMap(f => f) + }).flatten } //TODO: diff --git a/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/LockActor.scala b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/LockActor.scala index 4f36f002c..98d8564b4 100644 --- a/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/LockActor.scala +++ b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/LockActor.scala @@ -17,7 +17,6 @@ import org.sunbird.utils.Constants import java.text.SimpleDateFormat import java.util.concurrent.CompletionException import javax.inject.Inject -import scala.collection.immutable.{List, Map} import scala.concurrent.{ExecutionContext, Future} class LockActor @Inject()(implicit oec: OntologyEngineContext) extends BaseActor{ diff --git a/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/ObjectCategoryDefinitionActor.scala b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/ObjectCategoryDefinitionActor.scala index 4a3fd528f..a89e8575b 100644 --- a/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/ObjectCategoryDefinitionActor.scala +++ b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/ObjectCategoryDefinitionActor.scala @@ -7,6 +7,7 @@ import javax.inject.Inject import org.apache.commons.lang3.StringUtils import org.sunbird.actor.core.BaseActor import org.sunbird.common.{JsonUtils, Slug} +import org.sunbird.telemetry.logger.TelemetryManager import org.sunbird.common.dto.{Request, Response, ResponseHandler} import org.sunbird.common.exception.{ClientException, ResourceNotFoundException} import org.sunbird.graph.OntologyEngineContext @@ -58,7 +59,7 @@ class ObjectCategoryDefinitionActor @Inject()(implicit oec: OntologyEngineContex ResponseHandler.OK.put(Constants.IDENTIFIER, node.getIdentifier) }) } else throw new ClientException("ERR_INVALID_CATEGORY_ID", "Please provide valid category identifier") - }).flatMap(f => f) + }).flatten } else throw new ClientException("ERR_INVALID_REQUEST", "Invalid Request. Please Provide Required Properties!") } @@ -78,7 +79,7 @@ class ObjectCategoryDefinitionActor @Inject()(implicit oec: OntologyEngineContex DataNode.read(request) recoverWith { case e: ResourceNotFoundException => { val id = request.get(Constants.IDENTIFIER).asInstanceOf[String] - println("ObjectCategoryDefinitionActor ::: read ::: node not found with id :" + id + " | Fetching node with _all") + TelemetryManager.log("ObjectCategoryDefinitionActor ::: read ::: node not found with id :" + id + " | Fetching node with _all") if (StringUtils.equalsAnyIgnoreCase("POST", requestMethod) && !StringUtils.endsWithIgnoreCase(id, "_all")) { request.put(Constants.IDENTIFIER, id.replace(id.substring(id.lastIndexOf("_") + 1), "all")) DataNode.read(request) @@ -87,7 +88,7 @@ class ObjectCategoryDefinitionActor @Inject()(implicit oec: OntologyEngineContex } case e: CompletionException if e.getCause.isInstanceOf[ResourceNotFoundException] => { val id = request.get(Constants.IDENTIFIER).asInstanceOf[String] - println("ObjectCategoryDefinitionActor ::: read ::: node not found with id :" + id + " | Fetching node with _all") + TelemetryManager.log("ObjectCategoryDefinitionActor ::: read ::: node not found with id :" + id + " | Fetching node with _all") if (StringUtils.equalsAnyIgnoreCase("POST", requestMethod) && !StringUtils.endsWithIgnoreCase(id, "_all")) { request.put(Constants.IDENTIFIER, id.replace(id.substring(id.lastIndexOf("_") + 1), "all")) DataNode.read(request) diff --git a/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/TermActor.scala b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/TermActor.scala index 4915aad13..acfc32c2e 100644 --- a/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/TermActor.scala +++ b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/actors/TermActor.scala @@ -2,16 +2,15 @@ package org.sunbird.actors import org.apache.commons.lang3.StringUtils import org.sunbird.actor.core.BaseActor -import org.sunbird.common.{Platform, Slug} +import org.sunbird.common.Platform import org.sunbird.common.dto.{Request, Response, ResponseHandler} import org.sunbird.common.exception.{ClientException, ResponseCode } import org.sunbird.graph.OntologyEngineContext -import org.sunbird.graph.dac.enums.RelationTypes import org.sunbird.graph.dac.model.Node import org.sunbird.graph.nodes.DataNode import org.sunbird.graph.utils.NodeUtil import org.sunbird.utils.Constants -import org.sunbird.utils.taxonomy.RequestUtil +import org.sunbird.utils.taxonomy.{RequestUtil, TaxonomyUtil} import java.util import javax.inject.Inject import scala.concurrent.{ExecutionContext, Future} @@ -39,13 +38,13 @@ class TermActor @Inject()(implicit oec: OntologyEngineContext) extends BaseActor RequestUtil.restrictProperties(request) val frameworkId = request.getRequest.getOrDefault(Constants.FRAMEWORK, "").asInstanceOf[String] val categoryData = validateCategoryInstance(request) - val categoryId = generateIdentifier(frameworkId, request.getRequest.getOrDefault(Constants.CATEGORY, "").asInstanceOf[String]) + val categoryId = TaxonomyUtil.generateIdentifier(frameworkId, request.getRequest.getOrDefault(Constants.CATEGORY, "").asInstanceOf[String]) categoryData.flatMap(node => { if (null != node && StringUtils.equalsAnyIgnoreCase(node.getIdentifier, categoryId)) { val identifier = new util.ArrayList[String] var codeError = 0 var serverError = 0 - val index: Integer = getIndex(node) + val index: Integer = TaxonomyUtil.getNextSequenceIndex(node) var i: Integer = 0 val future = requestList.asScala.map(req => { val categoryList = new util.ArrayList[util.Map[String, AnyRef]] @@ -55,7 +54,7 @@ class TermActor @Inject()(implicit oec: OntologyEngineContext) extends BaseActor i = (i + 1) categoryList.add(relationMap) request.put("categories", categoryList) - request.getRequest.put(Constants.IDENTIFIER, generateIdentifier(categoryId, req.getOrDefault(Constants.CODE, "").asInstanceOf[String])) + request.getRequest.put(Constants.IDENTIFIER, TaxonomyUtil.generateIdentifier(categoryId, req.getOrDefault(Constants.CODE, "").asInstanceOf[String])) request.getRequest.putAll(req) DataNode.create(request).map(termNode => identifier.add(termNode.getIdentifier) @@ -98,14 +97,6 @@ class TermActor @Inject()(implicit oec: OntologyEngineContext) extends BaseActor } } - private def getIndex(node: Node): Integer = { - val indexList = (node.getOutRelations.asScala ++ node.getInRelations.asScala).filter(r => (StringUtils.equals(r.getRelationType, RelationTypes.SEQUENCE_MEMBERSHIP.relationName()) && StringUtils.equals(r.getStartNodeId, node.getIdentifier))) - .map(relation => { - relation.getMetadata.getOrDefault("IL_SEQUENCE_INDEX", 1.asInstanceOf[Number]).asInstanceOf[Number].intValue() - }) - if (indexList.nonEmpty) indexList.max + 1 else 1 - } - private def read(request: Request): Future[Response] = { validateCategoryInstance(request) validateTerm(request).map(node => { @@ -118,9 +109,9 @@ class TermActor @Inject()(implicit oec: OntologyEngineContext) extends BaseActor val termId = request.getContext.getOrDefault(Constants.TERM, "").asInstanceOf[String]; val frameworkId = request.getRequest.getOrDefault(Constants.FRAMEWORK, "").asInstanceOf[String] RequestUtil.restrictProperties(request) - val categoryId = generateIdentifier(frameworkId, request.getRequest.getOrDefault(Constants.CATEGORY, "").asInstanceOf[String]) + val categoryId = TaxonomyUtil.generateIdentifier(frameworkId, request.getRequest.getOrDefault(Constants.CATEGORY, "").asInstanceOf[String]) validateCategoryInstance(request) - request.getContext.put(Constants.IDENTIFIER, generateIdentifier(categoryId, termId)) + request.getContext.put(Constants.IDENTIFIER, TaxonomyUtil.generateIdentifier(categoryId, termId)) DataNode.update(request).map(node => { ResponseHandler.OK.put(Constants.IDENTIFIER, node.getIdentifier).put(Constants.VERSION_KEY, node.getMetadata.get("versionKey")) }) @@ -129,9 +120,9 @@ class TermActor @Inject()(implicit oec: OntologyEngineContext) extends BaseActor private def retire(request: Request): Future[Response] = { val termId = request.getContext.getOrDefault(Constants.TERM, "").asInstanceOf[String]; val frameworkId = request.getRequest.getOrDefault(Constants.FRAMEWORK, "").asInstanceOf[String] - val categoryId = generateIdentifier(frameworkId, request.getRequest.getOrDefault(Constants.CATEGORY, "").asInstanceOf[String]) + val categoryId = TaxonomyUtil.generateIdentifier(frameworkId, request.getRequest.getOrDefault(Constants.CATEGORY, "").asInstanceOf[String]) validateCategoryInstance(request) - request.getContext.put(Constants.IDENTIFIER, generateIdentifier(categoryId, termId)) + request.getContext.put(Constants.IDENTIFIER, TaxonomyUtil.generateIdentifier(categoryId, termId)) request.getRequest.put("status", "Retired") DataNode.update(request).map(node => { ResponseHandler.OK.put(Constants.IDENTIFIER, node.getIdentifier).put(Constants.VERSION_KEY, node.getMetadata.get("versionKey")) @@ -141,7 +132,7 @@ class TermActor @Inject()(implicit oec: OntologyEngineContext) extends BaseActor private def validateTerm(request: Request)(implicit oec: OntologyEngineContext, ec: ExecutionContext) = { val termId = request.getRequest.getOrDefault(Constants.TERM, "").asInstanceOf[String] if (termId.isEmpty()) throw new ClientException("ERR_INVALID_TERM_ID", s"Invalid TermId: '${termId}' for Term") - val categoryInstanceId = generateIdentifier(request.getRequest.getOrDefault(Constants.FRAMEWORK, "").asInstanceOf[String], request.getRequest.getOrDefault(Constants.CATEGORY, "").asInstanceOf[String]) + val categoryInstanceId = TaxonomyUtil.generateIdentifier(request.getRequest.getOrDefault(Constants.FRAMEWORK, "").asInstanceOf[String], request.getRequest.getOrDefault(Constants.CATEGORY, "").asInstanceOf[String]) val getTermReq = new Request() getTermReq.setContext(new util.HashMap[String, AnyRef]() { { @@ -150,9 +141,9 @@ class TermActor @Inject()(implicit oec: OntologyEngineContext) extends BaseActor }) getTermReq.getContext.put(Constants.SCHEMA_NAME, Constants.TERM_SCHEMA_NAME) getTermReq.getContext.put(Constants.VERSION, Constants.TERM_SCHEMA_VERSION) - getTermReq.put(Constants.IDENTIFIER, generateIdentifier(categoryInstanceId, termId)) + getTermReq.put(Constants.IDENTIFIER, TaxonomyUtil.generateIdentifier(categoryInstanceId, termId)) DataNode.read(getTermReq)(oec, ec).map(node => { - if (null != node && StringUtils.equalsAnyIgnoreCase(node.getIdentifier, generateIdentifier(categoryInstanceId, termId))) node + if (null != node && StringUtils.equalsAnyIgnoreCase(node.getIdentifier, TaxonomyUtil.generateIdentifier(categoryInstanceId, termId))) node else throw new ClientException("ERR_CHANNEL_NOT_FOUND/ ERR_FRAMEWORK_NOT_FOUND", s"Given channel/framework is not related to given category") })(ec) } @@ -162,7 +153,7 @@ class TermActor @Inject()(implicit oec: OntologyEngineContext) extends BaseActor val categoryId = request.getRequest.getOrDefault(Constants.CATEGORY, "").asInstanceOf[String] if (frameworkId.isEmpty()) throw new ClientException("ERR_INVALID_FRAMEWORK_ID", s"Invalid FrameworkId: '${frameworkId}' for Term ") if (categoryId.isEmpty()) throw new ClientException("ERR_INVALID_CATEGORY_ID", s"Invalid CategoryId: '${categoryId}' for Term") - val categoryInstanceId = generateIdentifier(frameworkId, categoryId) + val categoryInstanceId = TaxonomyUtil.generateIdentifier(frameworkId, categoryId) val getCategoryInstanceReq = new Request() getCategoryInstanceReq.setContext(new util.HashMap[String, AnyRef]() { { @@ -191,10 +182,4 @@ class TermActor @Inject()(implicit oec: OntologyEngineContext) extends BaseActor } } - private def generateIdentifier(scopeId: String, code: String): String = { - var id: String = null - if (StringUtils.isNotBlank(scopeId)) id = Slug.makeSlug(scopeId + "_" + code) - id - } - } \ No newline at end of file diff --git a/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/mangers/FrameworkManager.scala b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/managers/FrameworkManager.scala similarity index 98% rename from taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/mangers/FrameworkManager.scala rename to taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/managers/FrameworkManager.scala index cfb0023ff..efcc73c5b 100644 --- a/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/mangers/FrameworkManager.scala +++ b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/managers/FrameworkManager.scala @@ -1,4 +1,4 @@ -package org.sunbird.mangers +package org.sunbird.managers import java.util import org.apache.commons.lang3.StringUtils @@ -157,7 +157,7 @@ object FrameworkManager { Future(Map[String, AnyRef]()) else throw new ServerException("ERR_WHILE_FETCHING_HIERARCHY_FROM_CASSANDRA", "Error while fetching hierarchy from cassandra") - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } def copyHierarchy(request: Request)(implicit oec: OntologyEngineContext, ec: ExecutionContext): Future[Response] = { @@ -234,7 +234,7 @@ object FrameworkManager { }) ResponseHandler.OK.put("node_id", frameworkId) }) - }).flatMap(f => f) recoverWith { case e: CompletionException => throw e.getCause } + }).flatten recoverWith { case e: CompletionException => throw e.getCause } } private def getRequestMap(request: Request, metadata: util.Map[String, AnyRef], objectId: String, relationDef: Map[String, AnyRef]): Request = { diff --git a/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/utils/taxonomy/TaxonomyUtil.scala b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/utils/taxonomy/TaxonomyUtil.scala new file mode 100644 index 000000000..10184ed0e --- /dev/null +++ b/taxonomy-api/taxonomy-actors/src/main/scala/org/sunbird/utils/taxonomy/TaxonomyUtil.scala @@ -0,0 +1,38 @@ +package org.sunbird.utils.taxonomy + +import org.apache.commons.lang3.StringUtils +import org.sunbird.common.Slug +import org.sunbird.graph.dac.enums.RelationTypes +import org.sunbird.graph.dac.model.Node + +import scala.jdk.CollectionConverters._ + +/** + * Shared utility methods used across taxonomy actors (TermActor, CategoryInstanceActor, etc.) + * that were previously duplicated in each actor class. + */ +object TaxonomyUtil { + + /** + * Generates a slugified composite identifier from a scope (e.g. frameworkId or categoryId) + * and a code. Returns null when scopeId is blank to preserve backward compatibility. + */ + def generateIdentifier(scopeId: String, code: String): String = + if (StringUtils.isNotBlank(scopeId)) Slug.makeSlug(scopeId + "_" + code) else null + + /** + * Calculates the next available sequence index from a node's SEQUENCE_MEMBERSHIP + * out-relations. Returns 1 if the node has no existing sequence members, + * otherwise returns max(existing index) + 1. + */ + def getNextSequenceIndex(node: Node): Integer = { + val indexList = (node.getOutRelations.asScala ++ node.getInRelations.asScala) + .filter(r => + StringUtils.equals(r.getRelationType, RelationTypes.SEQUENCE_MEMBERSHIP.relationName()) && + StringUtils.equals(r.getStartNodeId, node.getIdentifier)) + .map(r => r.getMetadata + .getOrDefault("IL_SEQUENCE_INDEX", 1.asInstanceOf[Number]) + .asInstanceOf[Number].intValue()) + if (indexList.nonEmpty) indexList.max + 1 else 1 + } +} diff --git a/taxonomy-api/taxonomy-actors/src/test/scala/org/sunbird/managers/FrameworkManagerTest.scala b/taxonomy-api/taxonomy-actors/src/test/scala/org/sunbird/managers/FrameworkManagerTest.scala index efd2b0fea..11b904038 100644 --- a/taxonomy-api/taxonomy-actors/src/test/scala/org/sunbird/managers/FrameworkManagerTest.scala +++ b/taxonomy-api/taxonomy-actors/src/test/scala/org/sunbird/managers/FrameworkManagerTest.scala @@ -6,7 +6,7 @@ import org.sunbird.graph.OntologyEngineContext import org.sunbird.graph.dac.model.{Node, Relation, SubGraph} import java.util -import org.sunbird.mangers.FrameworkManager._ +import org.sunbird.managers.FrameworkManager._ import scala.collection.convert.ImplicitConversions._ import scala.concurrent.ExecutionContext