Sunday, January 26, 2020

Netbeans platform. Step 1.

In the modern world, the majority do not believe in desktop applications. They think that everything should be on the web or mobile. But there are cases when you need a software just for personal needs. For example hex editor, file manager, image editor, database clients. For such cases, desktop applications simply look better.

After some investigation, I've stopped on Netbeans' platform.

Main reasons why are:
  • Cross-platform.
  • Uses java.
  • Simpler than Eclipse.
Let's begin. Everything that is required is maven. There is an archetype to generate Netbeans Platform application. So, just execute in the terminal next command:

mvn archetype:generate 
    -DarchetypeGroupId=org.apache.netbeans.archetypes 
    -DarchetypeArtifactId=netbeans-platform-app-archetype 
    -DarchetypeVersion=1.22 
    -DgroupId=com.mycompany.project 
    -DartifactId=Demo

The next step is to build the project. Go to the directory Demo and execute
mvn install

That is all. In the directory Demo/application/target/demo/ you will find execution files. Just execute it to see your first window.


Saturday, January 25, 2020

VueJS? I guess no.

Two years ago I started VueJS + Vuetify project. At that moment it looked a good solution - a popular framework and rich library of components.

For today I can say that VueJS has few "features" that I really do not like and for the next project probably will take something else.

 Here is my list:
  • JS is pretty terrible. When you write a code it looks more or less acceptable. But when you need to support it, refactor, etc it became a nightmare. Typescript helps a lot but still, there is a big feeling that behind is JS. VueJS tries to swallow types on every step - when you access vuex store to get some values or to dispatch actions. Everything that's going on in the template is not type-safe. 
  • VueJS does not allow to declare events for components. There are two types of communication between components. From parents to children using properties. Children should declare own properties and then parents can use them to send information. The second type of communication is from children to parents using events. But in this case, there is no possibility to declare what events can be emitted from children to parents. So, you have to trust for documentation or to read the source code of the component.
  • There is not a proper inheritance. It is possible to extend the Html template using slots. Or to attach some common logic using mixins. But, for example, to extend form component to add additional text fields and some validation logic it is not possible.
So, these few features do not allow for me to reuse and combine my code as I want. At every moment I need to keep in the mind what types and where I use. Refactoring tools - I forgot what is that. All of that makes me slower and less productive. That's why next time I will try something else.

Saturday, October 20, 2018

Setting up work with MongoDB in Scala

MongoDB provides a reactive driver what allows to forget about thread pool when working with the database. Another reason to choose MongoDB it's to store or load case classes without writing a mapping between case class and document.
So, at the begin add a driver to the dependencies:
"org.mongodb.scala" %% "mongo-scala-driver"   % "2.2.1",
"io.netty"           % "netty-transport"      % "4.1.29.Final",
"io.netty"           % "netty-handler"        % "4.1.29.Final"
Create mongo client and open database:
private val mongoClient = MongoClient(config.getString("db.url"))
private val omsDatabase: MongoDatabase = mongoClient.getDatabase("mydb")
Let's define a simple case class
case class User(_id: ObjectId, name: String, password: String)
To save it in the database as it is we need to generate mapping to document and register it to the codec registry
import org.mongodb.scala.bson.codecs.DEFAULT_CODEC_REGISTRY
import org.bson.codecs.configuration.CodecRegistries.{ fromProviders, fromRegistries }
import org.mongodb.scala.bson.codecs.Macros._

private val codecRegistry = fromRegistries(fromProviders(classOf[User]), DEFAULT_CODEC_REGISTRY)
Now let's open collection with this codec registry
private val collection: MongoCollection[User] = db.withCodecRegistry(codecRegistry).getCollection("collectionName")
That is all, now we can save and load our case class
collection.insertOne(User(new ObjectId, "username", "password"))
val users: Observable[User] = collection.find()
But to case class User has two issues if you want to send it through http as json. First of all spray does not know how to work with class ObjectId, second - property _id open information what a database is behind. So, to (de)serialize ObjectId we need to define an implicit function
  implicit object ObjectIdFormat extends JsonFormat[ObjectId] {
    def write(x: ObjectId) = JsString(x.toString)
    def read(value: JsValue): ObjectId = value match {
      case JsString(x) => new ObjectId(x)
      case x => deserializationError("Expected hex string, but got " + x)
    }
  }
Next, to serialize _id as id we need to fix a list of names what spray extracs from case classes. Spray does it in the class spray.json.ProductFormats.
trait CustomProductFormats extends ProductFormats {
  this: StandardFormats =>

  override protected def extractFieldNames(classManifest: ClassManifest[_]): Array[String] = {
    val fields = super.extractFieldNames(classManifest)
    fields.map(name => if (name == "_id") "id" else name)
  }
}
And last step is to create a copy of spray.json.DefaultJsonProtocol and to use our CustomProductFormats instead of ProductFormats
object JsonFormats extends BasicFormats
  with StandardFormats
  with CollectionFormats
  with CustomProductFormats
  with AdditionalFormats

Saturday, October 6, 2018

Simple way to secure Akka Http rest services

One of the differences between Play Framework and Akka Http it is a security of the rest services. Akka Http has almost nothing for that. So, let's assume the next behavior for our application:
  •  All rest services except login should be secured
  • Login service returns JWT token as part of the header
  • Before to access any other services we have to validate JWT token in the header of a request
Our route without security has next view:
lazy val routes: Route =
pathPrefix("api") {
    pathPrefix("login") {
      post {
        parameter("email", "password") { (email, password) =>
          val loginResult: Future[Boolean] = loginService.login(email, password)
          onSuccess(loginResult) { result =>
            if(result) {
              respondWithHeader(RawHeader("TOKEN", createJwtToken(email))) {
                complete(StatusCodes.OK)
              }else{
                complete(StatusCodes.Unauthorized)
              }
            }
          }
        }
      }
    } ~
    pathPrefix("myService") {
      val data = myService.search()
      complite(data)
    }      
}
Now let's write a method which will wrap invocation of all services which we want to secure:
def authenticated: Directive1[String] =
    Directives.optionalHeaderValueByName("TOKEN").flatMap {
      case Some(jwt) if !isJwtTokenValid(jwt) =>
        Directives.complete(StatusCodes.Unauthorized -> "Invalid token.")
      case Some(jwt) if isJwtTokenExpired(jwt) =>
        Directives.complete(StatusCodes.Unauthorized -> "Token expired.")

      case Some(jwt) if !isJwtTokenExpired(jwt) => decodeJwtToken(jwt) match {
        case Some(email) =>
          Directives.provide(email)
        case None =>
          Directives.complete(StatusCodes.Unauthorized)
      }
      case _ => Directives.complete(StatusCodes.Unauthorized)
    }
And the last step is to invoke it before our services:

pathPrefix("api") {
    pathPrefix("login") {
      ...
    } ~
    authenticated{email =>    
      pathPrefix("myService") {
        val data = myService.search()
        complite(data)
      }      
    }
}

Sunday, March 18, 2018

Мої враження після 6 років використання GWT.

Для початку поясню чому вибір взагалі впав на GWT - це дуже просто, бо пристойного іншого не було. Всі сучасні javascript фреймворки(бібліотеки) на той час або ще не існували або тільки тільки зароджувалися. А GWT уже пропонував мінімізацію і оптимізацію коду, розбивку коду на модулі і завантаження за запитом, інтеграцію із мавеном, тестування, дебагінг. Зараз той самий angular чи reactjs можуть робити те саме, але в 2011 - 2012, наприклад, reactjs ще не існував.
І так, що мені подобається в GWT:
  • Мова програмування Java - це значить, що швидкість написання коду для клієнта і для сервера однакова, що підтримка зі сторони IDE максимальна. Один і той самий код можна використовувати як для клієнта так і для сервера.
  • Дебагінг - хоча в ранніх версіях від був кращий, бо браузери ще підтримували NPAPI GWT плагін дозволяв дебажити прямо в улюбленій IDE. В поточних версіях, так само як і в сучасному javascript, це робиться в developer tools і за допомогою source maps. До того ж підтримка в Chrome найкраща.
  • Інтеграція з мавеном - не потрібно нічого придумавати як все збирати і тестити. Наприклад компіляцію GWT можна виділити в окремий профайл.
  • Тести за допомогою JUnit - тести виконуються при компіляції, так що головне відділити код основної логіки від предствалення. Саме тому MVP краще підходить ніж MVC.
  • Можливість розширення - любий клас чи інтерфейс можна підмінити на свою реалізацію. Плюс код можна згенерувати. Наприклад робота із JSON в GWT схожа на роботу із XML DOM в яві. І щоб руками не пробігати весь JSON і не писати свої парсери, то такий код можна просто згенерувати на етапі компіляції.
  • Робота із помилками і логами - із коробки є можливість все відправляти на сервер, де все буде писатися уже в log4j тощо. Плюс якщо трішки послабити опції оптимізації, то можна добитися того, що стек трейси із клієнта будуть містити назву класів і номера рядків ще відбулася помилка. І все це буде писатися на сервері в лог файли.
  • Можливіть реалізувати плагіни - головно точка старту в GWT це клас який реалізує EntryPoint. Але якщо таких класів два? Обидва будуть виконані. Навіть якщо другий клас знайходиться в іншому jar файлі. Правда потрібні деякі маніпуляції із конфіг файлом. І виходить, що функціональність аплікухи можна розширяти просто добавляючии залежності в pom.xml.
  • Guava - на 99% підтримується в GWT.
Звісно ж у GWT ще багато гарних плюшок типу завантаження коду за запитом, i18n та l10n, інтеграція із javascript тощо. Але й з тим є деякі мінуси.
І ось вони
  • Повільна компіляція - наприклад наший проект на роботі збирається десь за 8 хвилин на 4-х ядерному core i7 з 16 гігами пам'яті. Звісно є всякі обхідні варіанти типу при розробці не проводити оптимізації і компіляти тільки для одного браузера. Але всерівно швидкість не така як angular.
  • Вихідний код всерівно більш роздутий і це зрозуміло, бо замість того щоб працювати із натівними структурами javascript, ми працюємо із різномантними згенерованими враперами. Наприклад ArrayList врапить доступ до javascript масиву і добавляє методи із інтерфейса List.
  • Повільний розвиток - GWT уже далеко не самий популярний фреймворк і як результат його розвиток іде трохи повільнішими кроками ніж хотілось би.

Кілька цікавих і безкоштовнийх бібліотек: guava-gwt, gwt-jackson, gwt highcharts, gwt-charts, GWT-OpenLayers 3, SmartGWT, gwtmaterialdesign, GWTP

Thursday, June 25, 2009

JPA в Google App Engine

Як відомо, робота зі стореджем в google app engine зроблена через JDO i JPA. В якості імплементації цих технологій google вибрав DataNucleus. Так от, якщо з JDO наче все більш чи меньше все працює, то з підтримкою JPA не все так добре. А саме, якщо у вас є параметризований запит і ви очікуєте отримати колекцію об'єктів, то, скоріше за все, у вас нічого не вийде. Щоб отримати колекцію з результатами, як правило, визивається javax.persistence.Query.getResultList(). Реалізація цього методу знаходиться у класі org.datanucleus.jpa.JPAQuery. Так от в момент виконання запиту до бази, ця реалізація замість того щоб передати список параметрів зі значеннями. передає null - query.executeWithMap(null). Ну і ви відповідно отримуєте NullPointerException.

Saturday, May 9, 2009

Помилки в логах JBoss

Досить цікава ситуація виникла, коли спробував підняти solr на JBoss. При старті JBoss почав в логи сипати кучу повідомлень про помилки. Після читання вікі та сорців solr виявилося, що solr в якості логера використовую jdk logger, який по дефолту всі повідоплення відправляє в консоль (sys.err). А JBoss, який використовує lo4j, в свою чергу перехоплює всі звернення до системних потоків, приводить їх до формату lo4j і ставить рівень логи як ERROR.
Щоб привести це в порядок, потрібно сворити файл logger.properties приблизно наступного виду
# Default global logging level:
.level= INFO

# Write to a file:
handlers= java.util.logging.FileHandler

# Write log messages in XML format:
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter 

# Log to the current working directory, with log files named solrxxx.log
java.util.logging.FileHandler.pattern = solr%u.log
і підправити опці з якими стартує JBoss.
JAVA_OPTS=%JAVA_OPTS% -Djava.util.logging.config.file=/logging.properties