@@ -7,17 +7,11 @@ import com.thenewmotion.ocpp.VersionFamily.{CsMessageTypesForVersionFamily, Csms
77import javax .net .ssl .SSLContext
88
99import scala .language .higherKinds
10- import scala .concurrent .{Await , ExecutionContext , Future , Promise }
11- import scala .concurrent .duration .DurationInt
12- import scala .util .{Failure , Success }
10+ import scala .concurrent .ExecutionContext
1311import com .thenewmotion .ocpp .{Version , Version1X , VersionFamily }
14- import com .thenewmotion .ocpp .json .api ._
1512import com .thenewmotion .ocpp .messages .{ReqRes , Request , Response }
1613import com .thenewmotion .ocpp .messages .v1x .{CentralSystemReq , CentralSystemReqRes , CentralSystemRes , ChargePointReq , ChargePointReqRes , ChargePointRes }
17- import com .thenewmotion .ocpp .messages .v20 ._
18- import com .typesafe .scalalogging .Logger
19- import org .slf4j .LoggerFactory
20-
14+ import com .thenewmotion .ocpp .messages .v20 .{CsmsRequest , CsmsResponse , CsmsReqRes , CsRequest , CsResponse , CsReqRes }
2115
2216trait OcppTest [VFam <: VersionFamily ] {
2317
@@ -156,177 +150,3 @@ object Ocpp20Test {
156150 with ocpp20transactions.Ops
157151}
158152
159- trait DocileConnection [
160- VFam <: VersionFamily ,
161- VersionBound <: Version , // shouldn't be necessary. we need some type level function from versionfamily to this
162- OutgoingReqBound <: Request ,
163- IncomingResBound <: Response ,
164- OutgoingReqRes [_ <: OutgoingReqBound , _ <: IncomingResBound ] <: ReqRes [_, _],
165- IncomingReqBound <: Request ,
166- OutgoingResBound <: Response ,
167- IncomingReqRes [_ <: IncomingReqBound , _ <: OutgoingResBound ] <: ReqRes [_, _]
168- ] extends MessageLogging {
169-
170- val receivedMsgManager : ReceivedMsgManager [OutgoingReqBound , IncomingResBound , OutgoingReqRes , IncomingReqBound , OutgoingResBound , IncomingReqRes ] =
171- new ReceivedMsgManager [OutgoingReqBound , IncomingResBound , OutgoingReqRes , IncomingReqBound , OutgoingResBound , IncomingReqRes ]()
172-
173- var incomingMessageHandlerStack : List [GenericIncomingMessageProcessor [
174- OutgoingReqBound , IncomingResBound , OutgoingReqRes , IncomingReqBound , OutgoingResBound , IncomingReqRes , _
175- ]] = List ()
176-
177- var ocppClient : Option [OcppJsonClient [
178- VFam ,
179- OutgoingReqBound ,
180- IncomingResBound ,
181- OutgoingReqRes ,
182- IncomingReqBound ,
183- OutgoingResBound ,
184- IncomingReqRes
185- ]] = None
186-
187- // TODO handle this more gently. The identity should be known after the script is started, regardless of whether the connection was established or not.
188- // that also has to do with being able to renew connections or disconnect and reconnect while executing a script
189- def chargePointIdentity : String = connectedCpId.getOrElse(sys.error(" Asked for charge point ID on not yet connected DocileConnection" ))
190-
191- var connectedCpId : Option [String ] = None
192-
193- private val connectionLogger = Logger (LoggerFactory .getLogger(" connection" ))
194-
195- final def pushIncomingMessageHandler (handler : GenericIncomingMessageProcessor [OutgoingReqBound , IncomingResBound , OutgoingReqRes , IncomingReqBound , OutgoingResBound , IncomingReqRes , _]): Unit = {
196- incomingMessageHandlerStack = handler :: incomingMessageHandlerStack
197- }
198-
199- final def popIncomingMessageHandler (): Unit = {
200- incomingMessageHandlerStack = incomingMessageHandlerStack.tail
201- }
202-
203- def connect (chargePointId : String ,
204- endpoint : URI ,
205- version : VersionBound ,
206- authKey : Option [String ]
207- )(implicit executionContext : ExecutionContext , sslContext : SSLContext ): Unit = {
208-
209- connectedCpId = Some (chargePointId)
210-
211- connectionLogger.info(s " Connecting to OCPP v ${version.name} endpoint $endpoint" )
212-
213- val connection = createClient(chargePointId, endpoint, version, authKey)(executionContext, sslContext) {
214- new RequestHandler [IncomingReqBound , OutgoingResBound , IncomingReqRes ] {
215- def apply [REQ <: IncomingReqBound , RES <: OutgoingResBound ](req : REQ )(implicit reqRes : IncomingReqRes [REQ , RES ], ec : ExecutionContext ): Future [RES ] = {
216-
217- incomingLogger.info(s " $req" )
218-
219- val responsePromise = Promise [OutgoingResBound ]()
220-
221- def respond (res : OutgoingResBound ): Unit = {
222- outgoingLogger.info(s " $res" )
223- responsePromise.success(res)
224- ()
225- }
226-
227- receivedMsgManager.enqueue(
228- GenericIncomingMessage [OutgoingReqBound , IncomingResBound , OutgoingReqRes , IncomingReqBound , OutgoingResBound , IncomingReqRes ](req, respond _)
229- )
230-
231- // TODO nicer conversion?
232- responsePromise.future.map(_.asInstanceOf [RES ])(ec)
233- }
234- }
235- }
236-
237- connection.onClose.foreach { _ =>
238- connectionLogger.info(s " Gracefully disconnected from endpoint $endpoint" )
239- ocppClient = None
240- }(executionContext)
241-
242- ocppClient = Some (connection)
243- }
244-
245- def sendRequestAndManageResponse [REQ <: OutgoingReqBound ](req : REQ )(
246- implicit reqRes : OutgoingReqRes [REQ , _ <: IncomingResBound ],
247- executionContext : ExecutionContext
248- ): Unit =
249- ocppClient match {
250- case None =>
251- throw ExpectationFailed (" Trying to send an OCPP message while not connected" )
252- case Some (client) =>
253- outgoingLogger.info(s " $req" )
254- client.send(req)(reqRes) onComplete {
255- case Success (res) =>
256- incomingLogger.info(s " $res" )
257- receivedMsgManager.enqueue(
258- GenericIncomingMessage [OutgoingReqBound , IncomingResBound , OutgoingReqRes , IncomingReqBound , OutgoingResBound , IncomingReqRes ](res)
259- )
260- case Failure (OcppException (ocppError)) =>
261- incomingLogger.info(s " $ocppError" )
262- receivedMsgManager.enqueue(
263- GenericIncomingMessage [OutgoingReqBound , IncomingResBound , OutgoingReqRes , IncomingReqBound , OutgoingResBound , IncomingReqRes ](ocppError)
264- )
265- case Failure (e) =>
266- connectionLogger.error(s " Failed to get response to outgoing OCPP request $req: ${e.getMessage}\n\t ${e.getStackTrace.mkString(" \n\t " )}" )
267- throw ExecutionError (e)
268- }
269- }
270-
271- /** Template method to be implemented by version-specific extending classes to establish a connection for that
272- * version of OCPP */
273- protected def createClient (
274- chargePointId : String ,
275- endpoint : URI ,
276- version : VersionBound ,
277- authKey : Option [String ]
278- )(implicit executionContext : ExecutionContext , sslContext : SSLContext ): RequestHandler [IncomingReqBound , OutgoingResBound , IncomingReqRes ] => OcppJsonClient [
279- VFam ,
280- OutgoingReqBound ,
281- IncomingResBound ,
282- OutgoingReqRes ,
283- IncomingReqBound ,
284- OutgoingResBound ,
285- IncomingReqRes
286- ]
287-
288-
289- def disconnect (): Unit = ocppClient.foreach { conn =>
290- Await .result(conn.close(), 45 .seconds)
291- }
292- }
293-
294- object DocileConnection {
295- def forVersion1x (): DocileConnection [
296- VersionFamily .V1X .type ,
297- Version1X ,
298- CentralSystemReq ,
299- CentralSystemRes ,
300- CentralSystemReqRes ,
301- ChargePointReq ,
302- ChargePointRes ,
303- ChargePointReqRes
304- ] = {
305- new DocileConnection [VersionFamily .V1X .type , Version1X , CentralSystemReq , CentralSystemRes , CentralSystemReqRes , ChargePointReq , ChargePointRes , ChargePointReqRes ] {
306- type VersionBound = Version1X
307-
308- override protected def createClient (chargePointId : String , endpoint : URI , version : Version1X , authKey : Option [String ])(implicit executionContext : ExecutionContext , sslContext : SSLContext ): RequestHandler [ChargePointReq , ChargePointRes , ChargePointReqRes ] => Ocpp1XJsonClient = { reqHandler =>
309- OcppJsonClient .forVersion1x(chargePointId, endpoint, List (version), authKey)(reqHandler)(executionContext, sslContext)
310- }
311- }
312- }
313-
314- def forVersion20 (): DocileConnection [
315- VersionFamily .V20 .type ,
316- Version .V20 .type ,
317- CsmsRequest ,
318- CsmsResponse ,
319- CsmsReqRes ,
320- CsRequest ,
321- CsResponse ,
322- CsReqRes
323- ] = {
324- new DocileConnection [VersionFamily .V20 .type , Version .V20 .type , CsmsRequest , CsmsResponse , CsmsReqRes , CsRequest , CsResponse , CsReqRes ] {
325- type VersionBound = Version .V20 .type
326-
327- override protected def createClient (chargePointId : String , endpoint : URI , version : Version .V20 .type , authKey : Option [String ])(implicit executionContext : ExecutionContext , sslContext : SSLContext ): RequestHandler [CsRequest , CsResponse , CsReqRes ] => Ocpp20JsonClient = { reqHandler =>
328- OcppJsonClient .forVersion20(chargePointId, endpoint, authKey)(reqHandler)(executionContext, sslContext)
329- }
330- }
331- }
332- }
0 commit comments