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

com.stratio.common.utils.repository.zookeeper.ZookeeperRepositoryComponent.scala Maven / Gradle / Ivy

/**
  * Copyright (C) 2015 Stratio (http://stratio.com)
  *
  * 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 com.stratio.common.utils.repository.zookeeper

import java.util.NoSuchElementException

import com.stratio.common.utils.repository.zookeeper.ZookeeperConstants._
import com.stratio.common.utils.config.ConfigComponent
import com.stratio.common.utils.logger.LoggerComponent
import com.stratio.common.utils.repository.RepositoryComponent
import org.apache.curator.framework.imps.CuratorFrameworkState
import org.apache.curator.framework.recipes.cache.{NodeCache, NodeCacheListener}
import org.apache.curator.framework.{CuratorFramework, CuratorFrameworkFactory}
import org.apache.curator.retry.ExponentialBackoffRetry
import org.apache.curator.utils.CloseableUtils
import org.json4s.Formats
import org.json4s.jackson.Serialization.read

import scala.collection.JavaConversions._
import scala.util.{Failure, Success, Try}

trait ZookeeperRepositoryComponent extends RepositoryComponent[String, Array[Byte]] {
  self: ConfigComponent with LoggerComponent =>

  val curatorFramework: CuratorFramework

  val repository = new ZookeeperRepository{}

  trait ZookeeperRepository extends Repository {

    private def curatorClient: CuratorFramework =
      ZookeeperRepository.getInstance(getZookeeperConfig)

    def get(id: String): Option[Array[Byte]] =
      Option(
        curatorClient
          .getData
          .forPath(id)
      )

    def getChildren(id: String): List[String] =
      curatorClient
        .getChildren
        .forPath(id).toList



    def exists(id: String): Boolean =
      Option(curatorClient
        .checkExists()
        .forPath(id)
      ).isDefined

    def create(id: String, element: Array[Byte]): Array[Byte] = {
      curatorClient
        .create()
        .creatingParentsIfNeeded()
        .forPath(id, element)

      get(id)
        .orElse(throw new NoSuchElementException(s"Something were wrong when retrieving element $id after create"))
        .get
    }

    def update(id: String, element: Array[Byte]): Unit =
      curatorClient
        .setData()
        .forPath(id, element)


    def delete(id: String): Unit =
      curatorClient
        .delete()
        .forPath(id)

    def getZookeeperConfig: Config =
      config.getConfig(ConfigZookeeper)
        .getOrElse(throw new ZookeeperRepositoryException("Zookeeper config not found"))

    def getConfig: Map[String, Any] =
      getZookeeperConfig.toMap

    def start: Boolean =
      Try(
        curatorClient.start()
      ).isSuccess

    def stop: Boolean = ZookeeperRepository.clean

    def getState: RepositoryState =
      curatorClient.getState match {
        case CuratorFrameworkState.STARTED => Started
        case CuratorFrameworkState.STOPPED => Stopped
        case CuratorFrameworkState.LATENT => NotStarted
        case _ => Unknown
      }

    def addListener[T <: Serializable](id: String, callback: (T, NodeCache) => Unit)
                                      (implicit jsonFormat: Formats, ev: Manifest[T]): Unit = {

      val nodeCache: NodeCache = new NodeCache(curatorClient, id)

      nodeCache.getListenable.addListener(
        new NodeCacheListener {
          override def nodeChanged(): Unit =
            Try(new String(nodeCache.getCurrentData.getData)) match {
              case Success(value) => callback(read[T](value), nodeCache)
              case Failure(e) => logger.error(s"NodeCache value: ${nodeCache.getCurrentData}", e)
            }
        }
      )
      nodeCache.start()
    }
  }

  private[this] object ZookeeperRepository {

    private var curatorClientOpt: Option[CuratorFramework] = None

    def getInstance(config: Config): CuratorFramework = synchronized {
      curatorClientOpt.getOrElse {
        Try {
          CuratorFrameworkFactory.builder()
            .connectString(
              config.getString(ZookeeperConnection, DefaultZookeeperConnection)
            )
            .connectionTimeoutMs(
              config.getInt(ZookeeperConnectionTimeout, DefaultZookeeperConnectionTimeout)
            )
            .sessionTimeoutMs(
              config.getInt(ZookeeperSessionTimeout, DefaultZookeeperSessionTimeout)
            )
            .retryPolicy(
              new ExponentialBackoffRetry(
                config.getInt(ZookeeperRetryInterval, DefaultZookeeperRetryInterval),
                config.getInt(ZookeeperRetryAttemps, DefaultZookeeperRetryAttemps)
              )
            )
            .build()
        } match {
          case Success(client: CuratorFramework) =>
            curatorClientOpt = Option(client)
            client
          case Failure(_: Throwable) =>
            throw ZookeeperRepositoryException("Error trying to create a new Zookeeper instance")
        }
      }
    }

    def clean: Boolean =
      Try {
        CloseableUtils.closeQuietly(curatorClientOpt.get)
        curatorClientOpt = None
      }.isSuccess
  }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy