Indexed Lazy Criteria Container (with cache), at verry alpha stage

Hi all,
i’m working on a “data managment” program, and i need to show some table feeded with rows from a database view (but i can’t and not want to store the view on the database itself, so i need to use a query).
I’m using JPA2 (with hibernate) to represent the db tables, and criteria query to retrieve data.

I know already exists
“JPA Criteria Lazy Container”
but it seem to me a bit tricky and verbose: I do not want to waste time to write a configuration for the container, i want to write the query and let the container guess everything else.

So…i wrote my own container, and i wish to introduce it to you as it may be usefull for someone and, well, I wouldn’t mind some help to improve it (i’m not a professional programmer but only a student, so any expert advice would be appreciable)

(i’m also Italian, so apologize for my english and for some italian comment/word in the code)

well, I think an example is worth a thousand words:


public class IndexedlazycontainerApplication extends Application {
	
	private class TestProvider extends IndexedLazyProvider{
		public TestProvider(EntityManager em) {
			super(em);			
			this.setIdProperty(this.getPropertyMetadata("id"));			
			this.addFilterMetadata(new Alias("", this.getFilterMetadata("nome")));
		}
		
		@Override
			protected CriteriaQuery<Tuple> createQuery(CriteriaBuilder cb) {
				CriteriaQuery<Tuple> q = cb.createTupleQuery();
				articolo = q.from(Articolo.class);
				categoria = articolo.join("categoria", JoinType.LEFT);
				q.multiselect(articolo.get("id").alias("id"),
						articolo.get("nome").alias("nome"),
						articolo.get("prezzo").alias("prezzo"),
						categoria.get("testo").alias("categoria"),
						articolo.get("quantita").alias("quantita"));
				return q;
			}
	}
	
	
	@Override
	public void init() {
		Window mainWindow = new Window("Indexedlazycontainer Application");
		
		EntityManagerFactory emf = Persistence.createEntityManagerFactory("hibernate");
		EntityManager entityManager = emf.createEntityManager();		
		
		Table table = new Table();
		
		table.setContainerDataSource(new IndexedLazyContainer(new TestProvider(entityManager)));
		
		mainWindow.addComponent(table);
		
		setMainWindow(mainWindow);
	}

}

as you can see, the Articolo class is one of mine project db table mapped with JPA.

before continuing, i need to share with you the source code (i’m not sure how i’m supposed to pack up a such thing, so…i just made a zip):
http://www.mediafire.com/file/bxan39ul0d87u8j/indexedLazyContainer.zip

to make it work you will need a working JPA2.0 model and slf4j for logging.


this.setIdProperty(this.getPropertyMetadata("id"));			
this.addFilterMetadata(new Alias("", this.getFilterMetadata("nome")));

are not even required, all can work also without, they are only there to demonstate what the container can do.

Explain all the container is a big work…i’ll just do sketch:

  • it’s readOnly, i don’t need to write back to db using the container, so i avoided a lot of work.

  • the IndexedLazyContainer itself is nothing but a wrapper

  • the real work is done by the inner IndexedLazyProvider that holds the query and the cache

  • to create a working provider is enough override the protected method createQuery and set the EntityManager from the constructor

  • the provider will read the query and guess the propertys and avalible filterIds

  • all items are loaded by index so they are represented by an instance of IndexedItemId that hold the index and, when the item is effectively loaded the table id(only if someone has set the right property with the setIdProperty method)

  • A filter can not share the id with the associated property (it can also be a more complex expression over more property or also over something that neither is a property, but the default generated of course share the name with the property)

  • to add a custom filter it’s only needed do pass a custom FilterMetadata extension to the addFilterMetadata method

  • it support ordering only trough the avalible property (i think it’s enough)

…i surely forgot someting, and i know this two words can’t explain wath the container actually does and how, but…if someone is interested i can explain more.

i know all this may seem bungled but…i’d like to share this with you but don’t wan’t to lose too much time if no one is interested in (also becouse it is in verry early state, just a good start, in my opinion)

i say it onece more: it’s absolutly not ready for production, although it seemed to me to work (at least for what I need)

update: I forgot to mention that some of the codes are written just to work (no time/will to write something better)

(English below)

Salve! Ho scritto il programma “JPA Criteria Lazy Container”. (Ho lavorato in Italia dodici anni fa e mi ricordo di qualque parola :slight_smile: )

Secondo me, il BeanTupleContainer dentro il package funziona come lei vuole: scriva solo la query e il Container indovinatà tutto. Non c’è niente da configurare, veramente. Guardero il suo programma nei prossimi giorni, sicuramente ci sone idee da capire. Mi scuso per il mio Italiano sbagliato ! Se lei vuole mandarmi e-mail, va à vedere la pagina Web GoogleCode per il JPA container.

(English)
I wrote the JPA Criteria container. There is no configuration at all, the container pretty much figures out everything, the only thing needed is to write the query. I will nevertheless look at your program in the coming days, no doubt there are ideas to borrow. If you want to send me e-mail about the container, I can be reached via the GoogleCode Web page.


(English below)

La ringrazio della risposta, e vorrei chiarire che non intendevo criticare o denigrare il “JPA Criteria Lazy Container”, l’ho citato semplicemente per far capire di cosa stavo parlando, visto che ricreo probabilmente solo alcune funzioni.
Dal codice di esempio che riporta la pagina dell’addon :
Source code for sample app
, nello specifico
BeanTupleSimpleFilteringApplication.java

mi era sembrato di capire che bisognasse creare i filtri a mano (anche quelli piu semplici, ricavati da una singola proprietà) e applicarli direttamente alla query nella definizione (in defineQuery). Oppure usando il secondo metodo (in BeanTupleCustomFilteringApplication.java) si dovesse fare eccessivamente riferimento alla struttura reale dei dati usando informazioni che non sono necessariamente disponibili a chi usa il container :

new FilterRestriction(Task.class.getSimpleName()+"."+Task_.name.getName(), FilterRestriction.Operation.LIKE, nameFilterValue)

i filtri mancano di astrazione, mentre come li avevo pensati io sarebbe possibile definire un filtro “strano” che corrisponda a un espressione complessa, ad esempio “Task.id = value OR Task.name LIKE %value% OR Task.autor LIKE %value%” che cerca, dato una stringa (value) un Task che abbia una corrispondenza in almeno uno dei 3 campi, senza che chi lo usa sappia realmente di cosa si tratta.

Comunque, probabilmente ho sottovalutato io il “JPA Criteria Lazy Container” e tutte queste cose le può fare. Ancora una volta, non voleva essere una critica o un “trovare un rimpiazzo” per il suo lavoro. E’ stato principalmente un mio esperimento didattico per vedere se riuscivo a scrivere un container funzionante che mi potesse essere utile.


(Englis)

Thank you for your answer, and I should clarify that I did not mean criticize or denigrate the “JPA Lazy Container Criteria,” I cite it simply to make understand what I was talking about, as I recreate probably only certain functions.
From the sample code that shows the addon page:

Source code for sample app
, specifically
BeanTupleSimpleFilteringApplication.java

I seemed to understand that we need to create the filters by hand (even simple ones, derived from a single property) and apply directly in the query definition (defineQuery). Or we can use the second method (in eanTupleCustomFilteringApplication.java) but i think we had to make too much reference to the real structure of data using information that is not necessarily available to those who use the Container:

 new FilterRestriction (Task.class.getSimpleName ()+"."+ Task_.name.getName (), FilterRestriction.Operation.LIKE, nameFilterValue) 

I think that the filters lack of abstraction, and as I had thought I would I can define a filter “strange” that corresponds to a complex expression, such as "value = Task.id Task.name OR LIKE% value% OR Task.autor LIKE% value% "that seeks, taken a string (value) that a Task has a match in at least one of the three fields, without who uses it really know what it is.

However, I’ve probably underestimated the "JPA Lazy Criteria Container "and all these things can be done. Once again, it did not want to be a criticism or a “find a replacement for your work”. It was primarily a teaching experiment to see if I could write a functional container that I could be useful to me.

Capisco adesso. Now I see what you want.

In the BeanTupleContainer, the method defineQuery is the same as your createQuery, and you can do all the interesting queries (and, or, subqueries, exists, whatever you want), exactly as you wrote them in your code (and it would work with .alias as well – the properties in the container would be named according to the alias).

However, the problem with your version of “defineQuery” is that articolo.get(“nome”) is fragile, it will break if the model changes (say to articolo.get(“artName”)) exactly as if you were writing SQL and changing the queries without changing the classes. In my examples, I made absolutely sure that I was using all the type safety features of JPA 2.0. To be safe, you should consider using the JPA2.0 static metamodel – if you change the Entity attributes, the code will not compile, and you will immediately the need to adjust your code.

So in short, you can actually use the BeanTupleContainer
exactly
as you are currently using yours. But BeanTupleContainer is also read-write, and I have made sure that nested entities work as well.

Similarly, when writing filters, you do not need to use the JPA2.0 static meta model, you could use .get(“nome”) just as you are.

I will still look at your code to see if I can learn new tricks and improve on mine. This is what open source is all about, indeed.

Well, it seem i need to look more closely to your container, i find out that I did not really understand it.

I use articolo.get(“nome”) just for test, because I have not yet figure out how to generate the static metamodel which i count to use in future (soon as I figured out how to generate it).
Using it nothing however change, my container simply generate the property from the criteria query alias, so it’s indipendent from the details of the model.

I simply made it readOnly as i didn’t need to use it to write, and also, i can’t immagine how to let the container figure out how to write back something that will result from a like “viewTable”, that is for it’s nature readOnly.
I use Tuple to load data such as i don’t want to load an Entity (or at least not all properties) to display only few fields in join with others entityes of wich also don’t need all the fields, so i use tuple to load only what i need.

I’m only at the beginning of JPA and such thing, but if i understood well it’s not possible to partially load an entity (exception made for others enityes collections referenced with proxy).