CAND NAG ARVIND GUDISEVA 1
EXCEPTION HANDLING IN SCALA
JAVA WAY OF EXCEPTION HANDLING IN SCALA
TRY / CATCH / FINALLY
Onlyone catch blockis neededandcasesare usedto handle individual exceptions
PRESENT CODE
def oracleSample(oraConnWeb: Connection): Unit = {
logger.info(" :: Start Def :: oracleSample :: ")
try {
val oraStmt = oraConnWeb.createStatement()
var sqlSelect = """select * from emp"""
logger.info("SQL: " + sqlSelect)
val rs = oraStmt.executeQuery(sqlSelect)
while (rs.next){
println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getString(3))
}
oraStmt.close()
}
catch {
case e: Throwable => e.printStackTrace()
}
logger.info(" :: End Def :: oracleSample :: ")
}
CAND NAG ARVIND GUDISEVA 2
MODIFIED CODE
def oracleSample(oraConnWeb: Connection): Unit = {
logger.info(" :: Start Def :: oracleSample :: ")
try {
val oraStmt = oraConnWeb.createStatement()
var sqlSelect = """select * from emp"""
logger.info("SQL: " + sqlSelect)
val rs = oraStmt.executeQuery(sqlSelect)
while (rs.next){
println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getString(3))
}
oraStmt.close()
}
catch {
case ex: java.sql.SQLException => throw new java.sql.SQLException("SQLException: " +
ex.printStackTrace())
case ex: oracle.net.ns.NetException => throw new
oracle.net.ns.NetException(1,ex.printStackTrace().toString)
case ex: java.net.UnknownHostException => throw new
java.net.UnknownHostException("UnknownHostException: " + ex.printStackTrace())
case ex: java.sql.SQLSyntaxErrorException => throw new
java.sql.SQLSyntaxErrorException("SQLSyntaxErrorException: " + ex.printStackTrace())
case ex: Exception => throw new Exception("Exception: " + ex.printStackTrace())
}
logger.info(" :: End Def :: oracleSample :: ")
}
IMPROVISED CODE
def oracleSample(oraConnWeb: Connection): Unit = {
logger.info(" :: Start Def :: oracleSample :: ")
try {
CAND NAG ARVIND GUDISEVA 3
val oraStmt = oraConnWeb.createStatement()
var sqlSelect = """select * from emp1"""
logger.info("SQL: " + sqlSelect)
val rs = oraStmt.executeQuery(sqlSelect)
while (rs.next){
println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getString(3))
}
oraStmt.close()
}
catch {
case ex: Exception => throw new CandAllExceptions(ex)
}
finally {
// Nothing
}
logger.info(" :: End Def :: oracleSample :: ")
}
WHAT IS THE PROBLEM?
Scala hasomittedCheckedExceptions. These exceptionsviolate SOLID –Open/ Close principle,
because we can’tthrow a newexceptioninasubclasswithoutpropagatingitaroundtoall the
existingclassesinthe hierarchy,aswell as methodscallingthose methods.
Scala’ssupportfor CheckedExceptionsisforcompatibilitywithJavacode. If we don’tintendtocall
a Scala code from Javacode,we shouldnotbe usingCheckedExceptions.
THROW NEW EXCEPTION
Throwingthe exceptionback tothe callingfunctionandhandlingthe exceptionsstackina
centralizedfashion.
PRESENT CODE
private def executeShell(shellStr: String) = {
logger.info(" :: Start Def :: executeShell :: ")
val shellCommand: String = shellStr
logger.info("Shell Command: " + shellCommand)
val sqoopProcess = Process(shellCommand).!!
logger.info("Shell Process: " + sqoopProcess)
logger.info(" :: End Def :: executeShell :: ")
}
IMPROVISED CODE
CAND NAG ARVIND GUDISEVA 4
private def executeShell(shellStr: String) = {
logger.info(" :: Start Def :: executeShell :: ")
try {
val shellCommand: String = shellStr
logger.info("Shell Command: " + shellCommand)
val stdOutput = new StringBuilder
val stdError = new StringBuilder
val processStatus: Int = shellCommand ! ProcessLogger(stdOutput append _, stdError append
_)
logger.info("Status Code: " + processStatus)
logger.info("Standard Output: " + stdOutput)
logger.info("Standard Error: " + stdError)
if(processStatus != 0){
val customCause = new RuntimeException("Non-zero Exit Code: (" + processStatus + ")")
val customException = new RuntimeException(customCause)
throw new CandCustomException(customException.getMessage, customException.getCause)
}
}
catch {
case ex: CandCustomException => throw new CandCustomException("CandCustomException: " +
ex.getMessage)
case ex: Exception => throw new CandAllExceptions(ex)
}
finally {
// Nothing
}
logger.info(" :: End Def :: executeShell :: ")
}
WHAT IS THE PROBLEM?
Shell / Processexceptionswere nevercaughtbyScalacode. Itwas handledbyJVM,whichwas
runningthe process. Enhance the code to use ProcessLoggerinsteadof Process.
PROCESS SHELL EXCEPTIONS:
Caused by: java.lang.RuntimeException: Unable to instantiate
org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient
java.io.IOException: Hive exited with status 1
USE PROCESSLOGGER INSTEAD OF PROCESS
INFO contrct.GenCustContract$: Status Code: 1
INFO contrct.GenCustContract$: Standard Output: Warning: Please set $ZOOKEEPER_HOME to the root of
your Zookeeper installation.
INFO contrct.GenCustContract$: Standard Error:
ERROR util.CandCustomException: Message: java.lang.RuntimeException: Non-zero Exit Code: (1)
CAND NAG ARVIND GUDISEVA 5
@THROWS ANNOTATION
Onlyuseful if Scalacode iscalledfromJavaProgram. Is notof muchvalue as we needto
encapsulate the callingfunctionwithatryand catch.
@throws(classOf[CandAllExceptions])
def testThrows (oraConnWeb: Connection) = {
logger.info(" :: Start Def :: testThrows :: ")
val i: Int = 1
val j: Int = 0
println("Result: " + i/j)
logger.info(" :: End Def :: testThrows :: ")
}
def callTest = {
try{
testThrows(OraDBCon.getNaiApplCon())
}
catch {
case ex: Exception => throw new CandAllExceptions(ex)
}
}
CUSTOM EXCEPTIONS
Everyexceptionhasamessage andcause. CustomExceptionare extendedfromRuntimeException.
Hence,message andcause needstobe populatedwhengeneratingaCustomException.
package com.cisco.cand.util
import grizzled.slf4j.Logger
class CandCustomException(message: String = null, cause: Throwable = null) extends
RuntimeException(CandCustomException.customMessage(message, cause), cause)
/**
* Created by Nag Arvind Gudiseva on 08-July-2016.
*/
object CandCustomException {
val logger = Logger(classOf[CandCustomException])
logger.info(" :: Start Object :: CandCustomException :: ")
def customMessage(message: String, cause: Throwable) = {
if (message != null) {
logger.error("Message: " + message)
message
}
else if (cause != null){
logger.error("Cause: " + cause.toString())
cause.toString()
}
else
CAND NAG ARVIND GUDISEVA 6
null
}
logger.info(" :: End Object :: CandCustomException :: ")
}
EXCEPTIONS STACK / CENTRALIZED HANDLING OF ALL EXCEPTIONS
The purpose of thisCentralizedExceptionhandlingistokeepthe catchclause of code cleanand
simple. Exceptiontype isrecognizedasperthe exceptioninstance andthe stacktrace isprinted.
package com.cisco.cand.util
import grizzled.slf4j.Logger
/**
* Created by Nag Arvind Gudiseva on 11-July-2016.
*/
object CandAllExceptions {
val logger = Logger(classOf[CandAllExceptions])
logger.info(" :: Start Object :: CandAllExceptions :: ")
class CandAllExceptions(exception: Exception) extends Exception {
if (exception.isInstanceOf[java.sql.SQLSyntaxErrorException]){
throw new java.sql.SQLSyntaxErrorException("SQLSyntaxErrorException: " +
exception.printStackTrace)
}
else if(exception.isInstanceOf[java.sql.SQLException]){
throw new java.sql.SQLException("SQLException: " + exception.printStackTrace)
}
else if (exception.isInstanceOf[oracle.net.ns.NetException]){
throw new oracle.net.ns.NetException(1,exception.printStackTrace.toString)
}
else if (exception.isInstanceOf[java.net.UnknownHostException]){
throw new java.net.UnknownHostException("UnknownHostException: " +
exception.printStackTrace)
}
else if (exception.isInstanceOf[org.apache.thrift.transport.TTransportException]){
throw new org.apache.thrift.transport.TTransportException("ThriftTransportException: " +
exception.printStackTrace)
}
else if (exception.isInstanceOf[java.lang.NullPointerException]){
throw new java.lang.NullPointerException("NullPointerException: " +
exception.printStackTrace)
}
else if (exception.isInstanceOf[java.io.IOException]){
throw new java.io.IOException("IOException: " + exception.printStackTrace)
}
else if (exception.isInstanceOf[java.lang.RuntimeException]){
throw new java.lang.RuntimeException("RuntimeException: " + exception.printStackTrace)
}
else if (exception.isInstanceOf[java.lang.ArithmeticException]){
throw new java.lang.ArithmeticException("ArithmeticException: " +
exception.printStackTrace)
}
else{
throw new Exception("Exception: " + exception.printStackTrace)
}
}
logger.info(" :: End Object :: CandAllExceptions :: ")
}
CAND NAG ARVIND GUDISEVA 7
FINAL NOTE
Enhancedexceptionshandlingcode isinjectedtothe existingScalacode. There isno change inthe
existingfunctionality.

Exception Handling in Scala

  • 1.
    CAND NAG ARVINDGUDISEVA 1 EXCEPTION HANDLING IN SCALA JAVA WAY OF EXCEPTION HANDLING IN SCALA TRY / CATCH / FINALLY Onlyone catch blockis neededandcasesare usedto handle individual exceptions PRESENT CODE def oracleSample(oraConnWeb: Connection): Unit = { logger.info(" :: Start Def :: oracleSample :: ") try { val oraStmt = oraConnWeb.createStatement() var sqlSelect = """select * from emp""" logger.info("SQL: " + sqlSelect) val rs = oraStmt.executeQuery(sqlSelect) while (rs.next){ println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getString(3)) } oraStmt.close() } catch { case e: Throwable => e.printStackTrace() } logger.info(" :: End Def :: oracleSample :: ") }
  • 2.
    CAND NAG ARVINDGUDISEVA 2 MODIFIED CODE def oracleSample(oraConnWeb: Connection): Unit = { logger.info(" :: Start Def :: oracleSample :: ") try { val oraStmt = oraConnWeb.createStatement() var sqlSelect = """select * from emp""" logger.info("SQL: " + sqlSelect) val rs = oraStmt.executeQuery(sqlSelect) while (rs.next){ println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getString(3)) } oraStmt.close() } catch { case ex: java.sql.SQLException => throw new java.sql.SQLException("SQLException: " + ex.printStackTrace()) case ex: oracle.net.ns.NetException => throw new oracle.net.ns.NetException(1,ex.printStackTrace().toString) case ex: java.net.UnknownHostException => throw new java.net.UnknownHostException("UnknownHostException: " + ex.printStackTrace()) case ex: java.sql.SQLSyntaxErrorException => throw new java.sql.SQLSyntaxErrorException("SQLSyntaxErrorException: " + ex.printStackTrace()) case ex: Exception => throw new Exception("Exception: " + ex.printStackTrace()) } logger.info(" :: End Def :: oracleSample :: ") } IMPROVISED CODE def oracleSample(oraConnWeb: Connection): Unit = { logger.info(" :: Start Def :: oracleSample :: ") try {
  • 3.
    CAND NAG ARVINDGUDISEVA 3 val oraStmt = oraConnWeb.createStatement() var sqlSelect = """select * from emp1""" logger.info("SQL: " + sqlSelect) val rs = oraStmt.executeQuery(sqlSelect) while (rs.next){ println(rs.getInt(1) + " " + rs.getString(2) + " " + rs.getString(3)) } oraStmt.close() } catch { case ex: Exception => throw new CandAllExceptions(ex) } finally { // Nothing } logger.info(" :: End Def :: oracleSample :: ") } WHAT IS THE PROBLEM? Scala hasomittedCheckedExceptions. These exceptionsviolate SOLID –Open/ Close principle, because we can’tthrow a newexceptioninasubclasswithoutpropagatingitaroundtoall the existingclassesinthe hierarchy,aswell as methodscallingthose methods. Scala’ssupportfor CheckedExceptionsisforcompatibilitywithJavacode. If we don’tintendtocall a Scala code from Javacode,we shouldnotbe usingCheckedExceptions. THROW NEW EXCEPTION Throwingthe exceptionback tothe callingfunctionandhandlingthe exceptionsstackina centralizedfashion. PRESENT CODE private def executeShell(shellStr: String) = { logger.info(" :: Start Def :: executeShell :: ") val shellCommand: String = shellStr logger.info("Shell Command: " + shellCommand) val sqoopProcess = Process(shellCommand).!! logger.info("Shell Process: " + sqoopProcess) logger.info(" :: End Def :: executeShell :: ") } IMPROVISED CODE
  • 4.
    CAND NAG ARVINDGUDISEVA 4 private def executeShell(shellStr: String) = { logger.info(" :: Start Def :: executeShell :: ") try { val shellCommand: String = shellStr logger.info("Shell Command: " + shellCommand) val stdOutput = new StringBuilder val stdError = new StringBuilder val processStatus: Int = shellCommand ! ProcessLogger(stdOutput append _, stdError append _) logger.info("Status Code: " + processStatus) logger.info("Standard Output: " + stdOutput) logger.info("Standard Error: " + stdError) if(processStatus != 0){ val customCause = new RuntimeException("Non-zero Exit Code: (" + processStatus + ")") val customException = new RuntimeException(customCause) throw new CandCustomException(customException.getMessage, customException.getCause) } } catch { case ex: CandCustomException => throw new CandCustomException("CandCustomException: " + ex.getMessage) case ex: Exception => throw new CandAllExceptions(ex) } finally { // Nothing } logger.info(" :: End Def :: executeShell :: ") } WHAT IS THE PROBLEM? Shell / Processexceptionswere nevercaughtbyScalacode. Itwas handledbyJVM,whichwas runningthe process. Enhance the code to use ProcessLoggerinsteadof Process. PROCESS SHELL EXCEPTIONS: Caused by: java.lang.RuntimeException: Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient java.io.IOException: Hive exited with status 1 USE PROCESSLOGGER INSTEAD OF PROCESS INFO contrct.GenCustContract$: Status Code: 1 INFO contrct.GenCustContract$: Standard Output: Warning: Please set $ZOOKEEPER_HOME to the root of your Zookeeper installation. INFO contrct.GenCustContract$: Standard Error: ERROR util.CandCustomException: Message: java.lang.RuntimeException: Non-zero Exit Code: (1)
  • 5.
    CAND NAG ARVINDGUDISEVA 5 @THROWS ANNOTATION Onlyuseful if Scalacode iscalledfromJavaProgram. Is notof muchvalue as we needto encapsulate the callingfunctionwithatryand catch. @throws(classOf[CandAllExceptions]) def testThrows (oraConnWeb: Connection) = { logger.info(" :: Start Def :: testThrows :: ") val i: Int = 1 val j: Int = 0 println("Result: " + i/j) logger.info(" :: End Def :: testThrows :: ") } def callTest = { try{ testThrows(OraDBCon.getNaiApplCon()) } catch { case ex: Exception => throw new CandAllExceptions(ex) } } CUSTOM EXCEPTIONS Everyexceptionhasamessage andcause. CustomExceptionare extendedfromRuntimeException. Hence,message andcause needstobe populatedwhengeneratingaCustomException. package com.cisco.cand.util import grizzled.slf4j.Logger class CandCustomException(message: String = null, cause: Throwable = null) extends RuntimeException(CandCustomException.customMessage(message, cause), cause) /** * Created by Nag Arvind Gudiseva on 08-July-2016. */ object CandCustomException { val logger = Logger(classOf[CandCustomException]) logger.info(" :: Start Object :: CandCustomException :: ") def customMessage(message: String, cause: Throwable) = { if (message != null) { logger.error("Message: " + message) message } else if (cause != null){ logger.error("Cause: " + cause.toString()) cause.toString() } else
  • 6.
    CAND NAG ARVINDGUDISEVA 6 null } logger.info(" :: End Object :: CandCustomException :: ") } EXCEPTIONS STACK / CENTRALIZED HANDLING OF ALL EXCEPTIONS The purpose of thisCentralizedExceptionhandlingistokeepthe catchclause of code cleanand simple. Exceptiontype isrecognizedasperthe exceptioninstance andthe stacktrace isprinted. package com.cisco.cand.util import grizzled.slf4j.Logger /** * Created by Nag Arvind Gudiseva on 11-July-2016. */ object CandAllExceptions { val logger = Logger(classOf[CandAllExceptions]) logger.info(" :: Start Object :: CandAllExceptions :: ") class CandAllExceptions(exception: Exception) extends Exception { if (exception.isInstanceOf[java.sql.SQLSyntaxErrorException]){ throw new java.sql.SQLSyntaxErrorException("SQLSyntaxErrorException: " + exception.printStackTrace) } else if(exception.isInstanceOf[java.sql.SQLException]){ throw new java.sql.SQLException("SQLException: " + exception.printStackTrace) } else if (exception.isInstanceOf[oracle.net.ns.NetException]){ throw new oracle.net.ns.NetException(1,exception.printStackTrace.toString) } else if (exception.isInstanceOf[java.net.UnknownHostException]){ throw new java.net.UnknownHostException("UnknownHostException: " + exception.printStackTrace) } else if (exception.isInstanceOf[org.apache.thrift.transport.TTransportException]){ throw new org.apache.thrift.transport.TTransportException("ThriftTransportException: " + exception.printStackTrace) } else if (exception.isInstanceOf[java.lang.NullPointerException]){ throw new java.lang.NullPointerException("NullPointerException: " + exception.printStackTrace) } else if (exception.isInstanceOf[java.io.IOException]){ throw new java.io.IOException("IOException: " + exception.printStackTrace) } else if (exception.isInstanceOf[java.lang.RuntimeException]){ throw new java.lang.RuntimeException("RuntimeException: " + exception.printStackTrace) } else if (exception.isInstanceOf[java.lang.ArithmeticException]){ throw new java.lang.ArithmeticException("ArithmeticException: " + exception.printStackTrace) } else{ throw new Exception("Exception: " + exception.printStackTrace) } } logger.info(" :: End Object :: CandAllExceptions :: ") }
  • 7.
    CAND NAG ARVINDGUDISEVA 7 FINAL NOTE Enhancedexceptionshandlingcode isinjectedtothe existingScalacode. There isno change inthe existingfunctionality.