tesseract: transversing Java Domains using JavaScript

For those who don’t know, I’ currently working on Instituto Superior Técnico at the Fenix Project. Fenix is a web application developed to do academic administration of the entire college, from course enrollment to parking.

This application is written in Java and uses a rich domain with more than 1000 distinct entities. One of the technologies that suports Fenix is the JVSTM (Java Versioned Software Transactional Memory) and the FenixFramework. This library allows to describe complex domains (both entities and relationships) in a syntax similar to java, and generates both the SQL1 code that creates/alter the tables, and the high level code that works with the application level.

One of the first problems that i faced was the domain dimension, and and the level of relations that exist. The team is used to opening the domain model file and scroll up and down searching for relations and classes, but this file has 17000+ lines. So one of the first things i developed was the Fenix Domain Browser, a domain structure navigator that presents the domain as a series of UML schemes. But this browser only can inspect the domain structure and not his instances. For that you normally use SQL queries, that makes navigating in a relation a slow and painful process (inner joins), or you build the entire stack from the domain up to the viewing level. None of this alternatives was ideal but was what we had.

Last year, in “Programação Avançada” (Advanced Programming), one of the course projects was to develop an interpretator of Java2. Developing this REPL3 was alot of fun, because we had time and implemented a bunch of features that weren’t required (dynamic functions, macros, etc.). After the project ended, I tried to connect this REPL with the Fenix Domain, but ending up not being a nice interaction. The main problem was Java’s typification. Each time you had to create a variable you had to declare types and probably do some kind of cast. Using Object variables only delays the problem since it had then to upper cast them to call any method. Other problem was the intersection library that I was using, JA doesn’t support Java 5 and that means no foreach’s, autoboxings, etc. For that reasons I stopped using it and put it aside.

Recently I was given the responsibility of reorganize an application used in IST called FeaRS. This is a Feature request system, but uses a voting system similar to digg or reddit. This application also uses the same domain technology than Fenix. When I finally put the application running on my server I wanted to inspect the instances on the domain so I remember of using the REPL I had developed. But this time I had one of those “What if”.

What if i used rhino to interact with the domain and use JavaScript as an interface language. After a week working on this I end up with Tesseract.

Tesseract is a REPL for any domain developed with the Fenix Framework. By default uses JavaScript but can also work with Java. This is essential because the team’s know how is in Java. Since Java and JavaScript are to some extent similar, allows them to use the this program and benefit from JavaScript dynamism and functional behavior, and if needed its possible to use Java in a particular task.

With the technology that we are currently work with, at the higher layers every relation is represented as lists. Since JavaScript is a functional language, where implemented functions that operate over java.util.Collection interface (map, reduce, filter, etc.). Although these functions receive a JavaScript function, these were implemented in Java, and run really fast.

On top of this I decided to implement a query language based upon Microsoft’s LINQ. This allows the developers to create queries with the same power that in SQL (actually more power, since JavaScript is Turing Complete and SQL isn’t), fully replacing it for read/write tasks. Structural changes in the domain are not possible yet. This language can work with both Java and JavaScript objects, since the interfaces to slots and methods are similar.

Examples

To start a query, an array (either a Java Collection, or something that implements a map method) is passed to the $ function. This will generate a Query object.

tes>$(FearsApp.getFears().getAdmins())
[query: size: 7]

Its important to notice that in this language we are always operating over lists of objects. Its possible to for the query return the result set as a Native JavaScript Object (toArray), or a Java List (toList). Now lets see from the admins who has voted in request, only limiting the result to 3:

tes>var z = $(FearsApp.getFears().getAdmins()).where(
function(user){
return find(user.getVoter(),
        function(voter){
        return voter.getVotesUsed() > 0;
        });
}).limit(3);
tes>z
[query: where$limit, size: 3]

To show the results we ask for a table:

tes> z.table();
+------------------------------------------+
| eu.ist.fears.server.domain.User@24c68a98 |
| eu.ist.fears.server.domain.User@1494cb8b |
| eu.ist.fears.server.domain.User@34bf1d3b |
+------------------------------------------+

By default a table can returns the result of calling toString on a object. Its possible to have another results:

tes> z.table(["username"]);
+----------+
| username |
+----------+
| istXXXXX |
| istXXXXY |
| istXXXXZ |
+----------+

The string can represent either a slot, a method or a getter (in this case “getUsername”). A table can have as many columns as desired:

tes> z.table([
{
label:"The UserName",
slot:"username"
},{
label: "Another UserName",
func:function(x) {
    return x.getUsername()
}
}
]);
+--------------+------------------+
| The UserName | Another UserName |
+--------------+------------------+
|     istXXXXX |         istXXXXX |
|     istXXXXY |         istXXXXY |
|     istXXXXZ |         istXXXXZ |
+--------------+------------------+

To travel in a relation one can use the select function when is expected to return a single object, or selectAll if the relation is *-to-Many. Those functions receives a string representing a slot, method or getter, or a function that is supposed to return the selected object:

tes> var t = $(FearsApp.getFears().getAdmins()).selectAll("getVoter").select("project");
tes> t.count();
55

Its important to note that selectAll will collect the results as they come, so its likely to contain repetitions if they occur in the relation. To select the unique objects in a list:

tes> t.distinct().count();
8

To see what object you have at one position you can it with elementAt but normally what you want is to inspect it. inspect will inspect the object at index you provide. This function only works with DomainObjects:

tes> t.inspect(1);
Instance of: eu.ist.fears.server.domain.Project
+---------------------+-----------------------------------------------------------------------------+
|                slot |                                                                       value |
+---------------------+-----------------------------------------------------------------------------+
|                name |                                                             CIIST-Taguspark |
|         description | Propostas e sugest?es para melhoramento dos servi?os do CIIST no Taguspark. |
| featuresIncrementID |                                                                           4 |
|        initialVotes |                                                                           5 |
|        listPosition |                                                                           6 |
+---------------------+-----------------------------------------------------------------------------+
+----------------+--------------------------------------------------------+
|       relation |                                             value/size |
+----------------+--------------------------------------------------------+
|          voter |        eu.ist.fears.server.domain.Voter(<lenght: 215>) |
|         author |            eu.ist.fears.server.domain.User(4294967497) |
|          admin |           eu.ist.fears.server.domain.User(<lenght: 0>) |
|       fearsApp |       eu.ist.fears.server.domain.FearsApp(17179869185) |
| featureRequest | eu.ist.fears.server.domain.FeatureRequest(<lenght: 4>) |
+----------------+--------------------------------------------------------+

If you need to know what is the structure of the entity, you can use entity:

tes> t.distinct().entity(1);
Entity eu.ist.fears.server.domain.Project
+---------------------+------------------+
|                slot |             type |
+---------------------+------------------+
|                name | java.lang.String |
|         description | java.lang.String |
| featuresIncrementID |              int |
|        initialVotes |              int |
|        listPosition |              int |
+---------------------+------------------+
+----------------+-------------------------------------------+--------------+
|       relation |                                      type | multiplicity |
+----------------+-------------------------------------------+--------------+
|          voter |          eu.ist.fears.server.domain.Voter |            * |
|         author |           eu.ist.fears.server.domain.User |         1..1 |
|          admin |           eu.ist.fears.server.domain.User |            * |
|       fearsApp |       eu.ist.fears.server.domain.FearsApp |            1 |
| featureRequest | eu.ist.fears.server.domain.FeatureRequest |            * |
+----------------+-------------------------------------------+--------------+

Another important thing is to know what kind of objects you have in your list. The function type returns a list with the classname of the objects:

tes> t.distinct().types();
[query: selectAll$select$distinct$types, size: 1]
tes> t.distinct().types().table();
+------------------------------------+
| eu.ist.fears.server.domain.Project |
+------------------------------------+

A query can be passed to another query, either as the starting list:

tes> $(z).where(function(x){ return x.getUsername().equals("istXXXXX"); });
[query: where, size: 1]

Or as a intersection to another query:

tes> $(range(0,20)).intersect($(range(5,15)));
[query: intersect, size: 10]

Performance

I executed some tests with this language and for the most part, performance is acceptable. The first iteration of a new relation is a bit slower due to the objects not being in cache.

The biggest relation that exists contains about 2 million objects. Using only integer, an iteration over a list with 2.5 millions objects took about 30 seconds. This means that the bottleneck is still in the connection to the database.

Future Work

One of the things i would like to implement is some kind of lazy evaluation. Currently each function call returns a new query object. That means that the query doesn’t generate side effects on the query object. So, its possible to create promises of execution for each new operation and when a effect requested the full set of operations would be minimized and optimized. But since this is going to be used in a development environment, this is not critical right now.

Using JavaScript as a interaction tool with Java can be useful because its not hard for a person who understands Java to work with JavaScript, and this language allows a more dynamic approach to software development in Java

Tesseract is available at githut here. Its NOT production ready, its even prior to a version 0.1 at this moment.


  1. There are attempts to use NoSQL systems, that in this kind of domain have greater performance ↩

  2. Actually was a bit different, the language was called µJava, but was essentially the same thing. ↩

  3. If you aren’t lispy enough it means Read-Eval-Print Loop ↩

Posted in Fenix, Programming | Tagged , | Leave a comment

JSC : A JavaScript Object System

As some of you might know, I’ve been working on a personal project for last 6 months, called Possimpable (working title).

This project is composed from 3 major components. Today I’m going to release some documentation about one of them.

Most parts of this project are written in JavaScript, including server-side. While I was attempting to write in a OO fashion, I started to feel that my code was written as a collection of JavaScript Hacks. Since that would inevitably leads to bug (and since JavaSCript is an asynchronous language, could lead to bugs hard to find). Other problem is that this project relies on a RMI between the client and the server, so I needed a way to simplify using it in JavaScript.

That made me start writing small scripts to pre-process code, but over time and several hacking sessions, I started having a small language on top of JavaScript. This language is called JSC.

I’m not releasing JSC compiler today because I’m not satisfied with the code in the current version. It still has some kinks that need to be worked on. I’m however requesting for comments.

I’m going to release 2 documents today. One is a presentation in Portuguese that I gave to grad. course. The other one is a small paper that describes the main topics for this language.

Posted in Possimpable, Python, Uncategorized | 2 Comments

∞ – recursive photo

No ultimo twittlis, após umas caipirinhas e umas imperiais, decidiram tirar um foto circular. Para quem não esteve, tiraram uma foto do próximo a tirar uma foto ao seu seguinte, e assim sucessivamente.

Como é chato andar a passar de pagina e fixe, fixe era adicionar umas animações panisgas, o que eu fiz foi pegar nessas fotos todas e juntar uns efeitos de jquery, em particular a biblioteca space gallery, e dar um aspecto janota ao que já estava no flickr, semelhante á time machine.

Assim, para quem quiser ver o resultado:

Posted in Uncategorized | 3 Comments

Eu e o forum da RNL

Hoje decidi deixar de usar o fórum da RNL. Como tal coloquei o seguinte post no forum da RNL:

Caríssimos, este vai ser a ultima vez que venho ao fórum. Estou completamente farto de ter posts censurados no fórum, por motivos absolutamente idiotas. Querem ter um fórum completamente higiénico, tenham. Eu vou para o outro fórum, onde embora sejam só caloiros a trocar projectos e a dizer porcaria, pelo menos ainda dá para conversar livremente. Quero te tenham atenção que já foram banidos utilizadores daqui pelas razões mais incríveis (p.e. ameaças porque a pessoa que leu o post não conseguiu perceber o fluxo de conversa), e até uma das pessoas mais interessadas no fórum, o aadsm. Alem disso, já não é a primeira vez que me sinto violado pela actual administração. Eu sei, porque me disseram, que já andaram a ler ficheiros da minha área do nexus. Acho isso uma completa quebra de privacidade e não sinto qualquer tipo de confiança em deixar qualquer trabalho meu num dos serviços providenciados pela actual administração. Este tipo de acções são deveras exasperantes. Já sei que os administradores vão dizer que dado que este serviço está debaixo da alçada do DEI têm que manter um certo tipo de nível.Mas a sobrevivência de qualquer comunidade está no seu crescimento orgânico. Ainda bem que já quase não tenho que ir ao “buraco” que é a RNL. Felizmente estou a acabar o curso e estou quase a não por os pés ai nunca mais. Não vou ler qualquer tipo de respostas. Se precisarem de falar comigo, enviem me um mail. Fiquem com o vosso fórum que eu vou para um sitio onde me sinto mais bem tratado.

A minha decisão foi motivada por vários factores mas aquilo que falo no post é o seguinte:

Os posts

Ontem fui sair á noite, e quando cheguei a casa decidi não me deitar e seguir directamente para a aula que tinha ás 8 da manhã. Como ainda eram 6 da manhã decidi escrever um pequeno post sobre a minha noite, acerca de uma rapariga que tinha visto nessa noite.

Qual é o meu espanto quando hoje sou informado que esse post tinha sido apagado.

Eu tenho uma tendência para quando chego a casa relativamente embriagado ir fazer post no fórum da RNL, em particular na thread da 5 da manhã. O que se passou é que a maioria destes posts tem sido apagados sucessivamente. O meu problema com isto é que esses posts embora mal escritos, nunca são ataques ou são ofensivos. Alias eu faço os nesta thread porque me parece indicada para este tipo de conteúdo, e em ultimo caso porque estou aborrecido, e me apetece partilhar o meu estado de mente.

A naturesa dos posts pode ser considerada algo brejeira. Mas a questão é que os posts foram colocados numa thread apropriada para este tipo de assuntos, e não são ofensivos. Neste ultimo o facto de usar duas expressões mais agressivas pode ter sido motivado pelo meu estado inebriado, mas tambem se tratava de utilizar expressões mais “coloridas” para melhor atingir o meu objectivo.

É prerrogativa da a administração da RNL poder achar este tipo de conteúdos não são úteis nem validos para o funcionamento do serviço mas eu acho que o fórum da RNL deve servir como uma espécie de agora, para não só partilhar ideias e criar discussões sobre os mais variados tópicos, mas também pode servir para aqueles momentos de “diarreia metal” e acho que é esta serendipicidade que dá ao fórum o seu valor.

A questão de privacidade

Eu sempre detestei usar Sistemas de Controlo de Versões. Tenho sempre o azar para estragar o repositorio central.

O semestre passado, durante o primeiro projecto da cadeira de PA, para facilitar o desenvolvimento decidi criar um repositório no nexus para cada elemento do grupo poder trabalhar em casa. Só que enquanto tentava instalar um hook no repositório para os outros elementos serem notificados por email quando era feito um commit para o repositório, apaguei a base de dados central a meio do projecto.

Para evitar outro evento destes, decidi criar um pequeno script que todos os dias criava um tgz e o guardava numa pasta, e usando screen meti o processo em background.

Porem a administração não permite que sejam executados processos em background no nexos. Passado 3 dias um dos administradores que eu conheço pessoalmente veio falar comigo através de IM a alertar para a situação e que tinha inspeccionado o ficheiro de forma a verificar qual era o intuito do processo.

E é aqui que para mim surge a tal quebra de privacidade.

O que se passa é para a administradores, inspeccionarem ficheiros que consideram suspeitos é natural. Para mim é uma política um bocado creepy e alem disso, acho estranho ser necessario necessário estas medidas extremas dado que estamos num sistema de numa organização fechada e é fácil de contactar os proprietários de uma conta quer por email ou telefone.

A titulo de exemplo, durante o meu primeiro ano no IST, eu e um colega meu criar-mos um programa em C que basicamente criava em ciclo infinito threads, e lembramos de colocar o programa a correr no antigo thor . O que aconteceu foi que o processo foi morto (das duas vezes) e fomos contactados por email pela administração para explicarmos o que se passava.

Obstante a isto, pode ser política daquela organização que os administradores inspeccionem ficheiros suspeitos, mas a verdade é que me senti algo violado por terem andado a olhar para o dito ficheiro.

Vamos por por hipótese que este script em vez de executar um simples backup executava uma tarefa qualquer mais estranha como fazer upload de qualquer coisa num site obscuro, e que a simples analise do seu conteúdo transmitia dados sensíveis. era perceptível qualquer tipo de informação sobre mim que não pretendia fosse conhecida (por exempo: preferencias sexuais, dados de saúde, problemas pessoais,etc.).

Convém ainda notar isto. Podia ser possível que o ficheiro em questão estava a gerar qualquer tipo de logs ou efeitos secundários que permitiam extrapolar o seu conteúdo. Neste caso claramente considero que não há qualquer tipo de violação da privacidade. A questão está é que inspeccionar o ficheiro é um acto explicito.

Aquilo que coloquei no post é uma opinião minha e sem duvida não é qualquer tipo de comentário injurioso. O que se passou foi o que estava aqui descrito em cima. Alem disso sinto que não vou usar aqueles serviços. Podem-se dar voltas e mais voltas, mas a questão essencial aqui é que foi aberto um ficheiro o qual não era propriedade da administração, embora a administração achasse que era sua responsabilidade ver o ficheiro.

E agora está na altura de meter este caso na gaveta que tenho mais para fazer na vida.

Posted in Uncategorized | 1 Comment

pnil – Translation from Python to Lisp

One of these days, while I was waiting for Fenix to finish compiling and catalina to restart, I decided to start developing a small python to lisp Translator just for fun.

Currently it just transforms (and badly, since it should do return-from insted of a return) a small times square function. It’s just a small proof of concept. It also is missing an object representing current context (variables defined, current function, etc.) But for all purposes, it works.

I also posted a presentation that i gave last year about this topic, but it’s in Portuguese.

Here are the files: Presentation pnil GitHub Repository

Posted in Lisp, Python | Leave a comment

O meu Verão.

Estudei até dar em doido para algo que não percebia. Aumentei de peso. Passei a uma cadeira de matematica. Acabei as cadeiras do curso. Só falta a tese. Tentei perder peso. Passei a primeira parte do verão a trabalhar, a segunda bêbado. Aumentei de peso e tentei perder ainda mais. A seguir trabalhei mais um bocado. E depois embebedei-me. O verão acabou. A tese & as aulas começaram. Continuo a tentar perder peso.

Estou de volta, e vou voltar a escrever posts. Agora vou beber um moscatel.

Posted in Cenas, Peso | 1 Comment

Semana 2: The Quickening

Guess what?

Peso

E o mais engraçado é que esta semana tive de comer pior. Houve uns dias onde não tinha comida e tive de comer pizzas e etc.

Semana 2

Semana 2

Posted in Peso, Uncategorized | Leave a comment

Project Possimpable…

…The place where the possible and the impossible meet to become… the Possimpable!
Possimpable

Possimpable

Posted in Cenas, Possimpable | 1 Comment

Etapa 1: A primeira semana…

Boas noticias! Diminui dois quilos, agora com 111,6 kg.

Durante a ultima semana tenho tentado ir de manhã ao ginásio, tento comer saladas e evitar fritos, hidratos de carbono (Pão, massas, etc.) e gorduras. Alem disso agora tenho sempre em casa fruta.

Outra coisa que me faz confusão é as bolachas. Não sei que bolachas comprar. As bolachas de agua e sal são perigosas, porque se lerem os rótulos com atenção, vão verificar que têm uma quantidade brutal de gorduras. A pessoa que me alertou para isto é um futuro médico. O que ele recomendou eram bolachas maria. Mas o problema é que essa bolacha é um bocado boring… Alguém tem conselhos em nesta temática?

Não tenho tido muita fome, mas de vez em quando dá me vontade comer, mas sem necessidade.

De qualquer maneira vamos a ver daqui a uma semana como é que as coisas vão estar…

Etapa 1

Etapa 1

Posted in Peso, Uncategorized | Tagged , | 1 Comment

OK. Admito, estou gordo…

Não estou interessado em tornar este post numa espécie de Oprah. Basicamente é mais interessante colocar isto aqui do que num moleskine.

Estou a pesar neste momento 113,9kg.

Durante os dois últimos anos, e principalmente, no último, o meu peso tem se vindo a deteriorar.

Para quem não sabe este è relativamente o peso que eu tinha no verão de 2005. Nesse ano, após um setressante semestre, decidi fazer uma dieta. Como tal fui a uma Persona (hey, foi por causa de um amigo meu de infância, que também tinha feito lá a dieta), e passaram me um plano de dieta. Eu não tinha beneces nenhumas. Não havia doces, pao, ou qualquer tipo de hibratos de carbono. Não pedi para me meterem doces ou outras porcarias na dieta.

Nesse verão, de 20-tal de julho a 10-tal de setembro, perdi perto de 30kg. Desci de uns 117 para 93. E estava realmente magro.estava tão magro que foi necessário comprar roupa nova O que me ajudou foi que estava em casa dos meus país. Segundo me lembro, eu estava realmente motivado para perder peso. Durante esse período, apenas me lembro de ter fome durante o segundo dia de dieta e nunca a quebrei.

Antes

Depois

Depois

Fast foward para agora. Eu não sei porquê mas não consigo manter uma dieta. Durante este ano implorei a minha mãe que me inscrevesse um ginasio, e ela cedeu. Mas devido á elevada carga de trabalho que tenho, ainda não consegui ir lá um mês seguido.

De qualquer maneira isto é o inicio de uma épica batalha entre eu e … mim mesmo. Vou lutar em cada refeição, em cada lanche, em cada pequeno-almoço, até mesmo em cada “fiquei insatisfeito, deixa-la comer mais qualquer coisa“! O meu primeiro objectivo é perder algum peso até dia 1 de Agosto.

Aqui fica o inicio…

A partida

Posted in Peso | Tagged , | 1 Comment
  • Flickr Photos

    Robots novos no L2FRecursive PhotoIMG_0130IMG_0183IMG_0182IMG_0181

    More Photos