All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
cc.otavia.sql.Connection.scala Maven / Gradle / Ivy
/*
* Copyright 2022 Yan Kun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cc.otavia.sql
import cc.otavia.core.actor.ChannelsActor.ChannelEstablished
import cc.otavia.core.actor.SocketChannelsActor
import cc.otavia.core.actor.SocketChannelsActor.Connect
import cc.otavia.core.channel.{Channel, ChannelAddress}
import cc.otavia.core.message.*
import cc.otavia.core.stack.*
import cc.otavia.core.stack.helper.*
import cc.otavia.sql.Authentication
import cc.otavia.sql.statement.*
import java.net.{ProtocolFamily, StandardProtocolFamily}
import scala.language.unsafeNulls
class Connection(
url: String,
info: Map[String, String],
driverName: Option[String] = None,
override val family: ProtocolFamily = StandardProtocolFamily.INET
) extends SocketChannelsActor[Connection.MSG] {
private var channel: ChannelAddress = _
private var driver: Driver = _
private var connectOptions: ConnectOptions = _
private var authenticated: Boolean = false
private var authenticationException: AuthenticationException = _
def this() = this(null, null)
def this(url: String, user: String, password: String) = this(url, Map("user" -> user, "password" -> password))
override protected def initChannel(channel: Channel): Unit = {
driver.setChannelOptions(channel)
channel.pipeline.addLast(driver)
}
override protected def isBarrierCall(call: Call): Boolean = call.isInstanceOf[Authentication]
override protected def afterMount(): Unit = if (url != null) this.noticeSelfHead(Authentication(url, info))
override protected def resumeAsk(stack: AskStack[Connection.MSG]): StackYield = {
stack match
case stack: AskStack[?] if stack.ask.isInstanceOf[Authentication] =>
handleAuthentication(stack.asInstanceOf[AskStack[Authentication]])
case stack: AskStack[?] if stack.ask.isInstanceOf[SimpleQuery[?]] =>
handleSimpleQuery(stack.asInstanceOf[AskStack[SimpleQuery[Reply]]])
case stack: AskStack[?] if stack.ask.isInstanceOf[PrepareQuery[?]] =>
handlePrepareQuery(stack.asInstanceOf[AskStack[PrepareQuery[Reply]]])
}
override protected def resumeNotice(stack: NoticeStack[Connection.MSG & Notice]): StackYield =
stack.state match
case _: StartState =>
val auth = stack.notice.asInstanceOf[Authentication]
createDriver(auth.driver, auth.url, auth.info)
stack.suspend(connect(connectOptions.socketAddress, None))
case state: ChannelFutureState if state.id == 0 => // waiting to authentication
channel = state.future.channel
val authState = ChannelFutureState(1)
channel.ask(stack.notice.asInstanceOf[Authentication], authState.future)
stack.suspend(authState)
case state: ChannelFutureState => // return authenticate result
if (state.future.isSuccess) {
authenticated = true
stack.`return`()
} else {
authenticationException = new AuthenticationException(state.future.causeUnsafe)
logger.error(s"Database[$url] authenticate failed! ", authenticationException)
stack.`return`()
}
private def handleAuthentication(stack: AskStack[Authentication]): StackYield =
stack.state match
case _: StartState => // waiting for socket connected
val auth = stack.ask
createDriver(auth.driver, auth.url, auth.info)
stack.suspend(connect(connectOptions.socketAddress, None))
case state: ChannelFutureState if state.id == 0 => // waiting to authentication
channel = state.future.channel
val authState = ChannelFutureState(1)
channel.ask(stack.ask, authState.future)
stack.suspend(authState)
case state: ChannelFutureState => // return authenticate result
if (state.future.isSuccess) {
authenticated = true
stack.`return`(ChannelEstablished(channel.id))
} else {
authenticationException = new AuthenticationException(state.future.causeUnsafe)
stack.`throw`(ExceptionMessage(authenticationException))
}
private def createDriver(driverName: Option[String], url: String, info: Map[String, String]): Unit = {
val factory = driverName match
case Some(name) => DriverManager.getDriverFactory(name)
case None => DriverManager.defaultDriver(url)
connectOptions = factory.parseOptions(url, info)
driver = factory.newDriver(connectOptions)
}
private def handleSimpleQuery(stack: AskStack[SimpleQuery[Reply]]): StackYield = {
stack.state match
case _: StartState =>
val query = stack.ask
val channelState = ChannelFutureState()
channel.ask(query, channelState.future)
stack.suspend(channelState)
case state: ChannelFutureState =>
if (state.future.isSuccess) stack.`return`(state.future.getNow.asInstanceOf[Reply])
else stack.`throw`(ExceptionMessage(state.future.causeUnsafe))
}
private def handlePrepareQuery(stack: AskStack[PrepareQuery[Reply]]): StackYield = {
stack.state match
case _: StartState =>
val query = stack.ask
val channelState = ChannelFutureState()
channel.ask(query, channelState.future)
stack.suspend(channelState)
case state: ChannelFutureState =>
if (state.future.isSuccess) stack.`return`(state.future.getNow.asInstanceOf[Reply])
else stack.`throw`(ExceptionMessage(state.future.causeUnsafe))
}
private def handleCursor(stack: AskStack[ExecuteCursor[?]]): StackYield = {
???
}
}
object Connection {
type MSG = Authentication | SimpleQuery[? <: Reply] | PrepareQuery[? <: Reply]
}