pepuch
pepuch

Reputation: 6516

Cache/optimize dynamic views which load data from database

I've created article composite component which I use in almost every page. This CC loads data from database and insterts it in a view. To use this CC I need to only call <cc:article id="article-id"/> so it's really simple to use. The problem is that I need to load data from database on every request so it is not the best solution. I want to optimize it but I don't know how. Before I will write whats ideas I've got to solve this problem lets see how most important parts of cc looks like:

This is CC

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" ...>

    <h:body>
        <cc:interface componentType="articleFacesComponent">
            <cc:attribute name="articleId" required="true" />
            <cc:attribute name="editable" type="boolean" default="false" required="false" />
            <cc:attribute name="styleClass" default="article" required="false" />
        </cc:interface>
        <cc:implementation>
            <h:outputStylesheet library="cc" name="js/article.css" />
            <div class="#{cc.attrs.styleClass}">
                ...
                    <!-- here I load article from FacesComponent -->
                    <h:outputText value="#{cc.article.text}" escape="false" />
                ...
            </div>
        </cc:implementation>
    </h:body>
</html>

This is FacesComponent used by cc

import entity.Article;
import javax.faces.component.FacesComponent;
import javax.faces.component.UINamingContainer;
import javax.persistence.EntityManager;
import service.DatabaseManager;

@FacesComponent("articleFacesComponent")
public class ArticleFacesComponent extends UINamingContainer {

    private Article article;
    private EntityManager em;

    public Article getArticle() {
        if (article==null) {
            init();
        }
        return article;
    }

    private void init() {
        em = DatabaseManager.getInstance().em();
        Object idObj = getAttributes().get("articleId");
        if (idObj != null) {
            String id = String.valueOf(idObj);
            if (id != null) {
                article = em.find(Article.class, id);
                if (article == null) {
                    article = new Article(id);
                }
            }
        }
    }

}

First of all I want to write what is the problem with this solution:

  1. I need to load data from database on every request
  2. FacesComponent looks ugly because I can't inject managed beans into it or even call PostContruct.
  3. In getArticle() I need to call init() every time because cc attributes are not visible in constructor.

How it should work?

  1. FacesComponent should't load data from database.
  2. I should be able to inject managed beans into FacesComponent. Is it possible?
  3. I should be able to call PostContruct in FacesComponent.

What ideas I've got so solve this problem?

  1. I think that I can create thread safety class which will load data from database and store it in a List. The pros of this solution is that I will load data from db only once but the cons are that I need to keep all articles in memory. Now I've got about 30 articles so it can work in that way but in the future there may be 300 or 3000 articles so it will waste memory.
  2. Cache views. Create solution to create static views and store them in cache directory from where they will be loaded. Maybe JSF has got some cache solution for dynamic views?

Upvotes: 1

Views: 248

Answers (1)

BalusC
BalusC

Reputation: 1108632

As to the concrete question, the JSF utility library OmniFaces has an <o:cache> component which allows you to cache the component's generated HTML output in the session or even the application scope on a specific key for a determined period. See also the showcase page.

Upvotes: 1

Related Questions