Package com.gentics.cr

Source Code of com.gentics.cr.CachedCRRequestProcessor

package com.gentics.cr;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;

import org.apache.jcs.JCS;
import org.apache.jcs.access.exception.CacheException;
import org.apache.log4j.Logger;

import com.gentics.api.lib.datasource.Datasource;
import com.gentics.api.lib.datasource.DatasourceException;
import com.gentics.api.lib.datasource.Datasource.Sorting;
import com.gentics.api.lib.exception.ParserException;
import com.gentics.api.lib.expressionparser.ExpressionParserException;
import com.gentics.api.lib.expressionparser.filtergenerator.DatasourceFilter;
import com.gentics.api.lib.resolving.Resolvable;
import com.gentics.cr.exceptions.CRException;
import com.gentics.cr.monitoring.MonitorFactory;
import com.gentics.cr.monitoring.UseCase;

/**
* CachedCRRequestProcessor fixes a bug in Gentics PortalConnector which
* prevents the PortalConnector from caching prefill attributes. Gentics Ticket
* ID is #38183.
* Last changed: $Date: 2010-04-01 15:24:02 +0200 (Do, 01 Apr 2010) $
* @version $Revision: 541 $
* @author $Author: supnig@constantinopel.at $
*/
public class CachedCRRequestProcessor extends RequestProcessor {

  /**
   * Log4j logger for error and debug messages.
   */
  private static Logger logger = Logger.getLogger(CachedCRRequestProcessor.class);

  /**
   * JCS cache for our results.
   */
  private static JCS resultCache;

  /**
   * Map with base {@link Resolvable}s for the filter.
   */
  private HashMap<String, Resolvable> resolvables = null;

  /**
   * Attribute to check if an object is up to date. So the attribute should
   * change whenever the object is changed.
   */
  private static final String UPDATEATTRIBUTE = "updatetimestamp";

  /**
   * Create a new instance of CRRequestProcessor.
   * @param config TODO javadoc
   * @throws CRException TODO javadoc
   */
  public CachedCRRequestProcessor(final CRConfig config) throws CRException {
    super(config);
  }

  /**
   * Fetch the matching objects using the given CRRequest.
   * @param request TODO javadoc
   * @param doNavigation defines if to fetch child elements
   * @return resulting objects
   * @throws CRException TODO javadoc
   */
  public final Collection<CRResolvableBean> getObjects(final CRRequest request, final boolean doNavigation)
      throws CRException {
    UseCase getObjectCase = MonitorFactory.startUseCase("CRRequestProcessor.getObjects(" + config.getName() + ")");
    Datasource ds = null;
    DatasourceFilter dsFilter;
    Vector<CRResolvableBean> collection = new Vector<CRResolvableBean>();
    if (request != null) {
      // Parse the given expression and create a datasource filter
      try {
        ds = this.config.getDatasource();
        if (ds == null) {
          throw (new DatasourceException("No Datasource available."));
        }

        dsFilter = request.getPreparedFilter(config, ds);
        // add base resolvables
        if (this.resolvables != null) {
          for (Iterator<String> it = this.resolvables.keySet().iterator(); it.hasNext();) {
            String name = it.next();
            dsFilter.addBaseResolvable(name, this.resolvables.get(name));
          }
        }

        String[] prefillAttributes = request.getAttributeArray();
        int first = request.getStart().intValue();
        int last = request.getCount().intValue();
        Sorting[] sorting = request.getSorting();
        // do the query
        Collection<Resolvable> col = getResult(ds, dsFilter, prefillAttributes, first, last, sorting);

        // convert all objects to serializeable beans
        if (col != null) {
          for (Iterator<Resolvable> it = col.iterator(); it.hasNext();) {
            CRResolvableBean crBean = new CRResolvableBean(it.next(), request.getAttributeArray());
            if (this.config.getFolderType().equals(crBean.getObj_type()) && doNavigation) {
              // Process child elements
              String fltr = "object.folder_id=='" + crBean.getContentid() + "'";
              if (request.getChildFilter() != null) {
                fltr += "AND (" + request.getChildFilter() + ")";
              }
              // If object is a folder => retrieve the childs of the object
              CRRequest childReq = request.Clone();
              childReq.setRequestFilter(fltr);
              crBean.fillChildRepository(this.getNavigation(childReq));
            }
            collection.add(this.replacePlinks(crBean, request));
          }
        }

      } catch (ParserException e) {
        e.printStackTrace();
        throw new CRException("ParserException", e.getMessage());
      } catch (ExpressionParserException e) {
        e.printStackTrace();
        throw new CRException("ExpressionParserException", e.getMessage());
      } catch (DatasourceException e) {
        e.printStackTrace();
        throw new CRException("DatasourceException", e.getMessage());
      } finally {
        CRDatabaseFactory.releaseDatasource(ds);
        getObjectCase.stop();
      }
    }
    return collection;
  }

  /**
   * This Method implements a caching due to a lack of performance in the
   * CNDatasource when getting a large result with prefilled Attributes.
   * When the Issue is solved we can remove this method. Gentics Ticket ID is
   * #38183.
   * @param ds {@link Datasource} to get the objects from
   * @param dsFilter filter describing the objects to fetch from the
   * {@link Datasource}
   * @param prefillAttributes attributes that should be prefilled with the
   * result.
   * @param first index of the first item to fetch
   * @param last index of the last item to fetch. Use <code>-1</code> to get all
   * objects
   * @param sorting {@link Sorting} that should be used.
   * @return {@link Collection} of {@link Resolvable}s described by the filter.
   */
  private Collection<Resolvable> getResult(final Datasource ds, final DatasourceFilter dsFilter,
      final String[] prefillAttributes, final int first, final int last, final Sorting[] sorting) {
    UseCase getResultCase = MonitorFactory.startUseCase("CRRequestProcessor.getResult(" + config.getName() + ")");
    Collection<?> result;
    Collection<Resolvable> checkCacheResult;
    Collection<Resolvable> collection = null;
    Collection<Resolvable> cachedResult;
    String cacheKey = config.getName() + "-" + dsFilter.getExpressionString();

    try {
      UseCase getResultFastCase = MonitorFactory.startUseCase("CRRequestProcessor.getResult(" + config.getName()
          + ")#fastResult");
      checkCacheResult = toResolvableCollection(ds.getResult(dsFilter, new String[] {}, first, last, sorting));
      getResultFastCase.stop();

      UseCase getResultCacheCase = MonitorFactory.startUseCase("CRRequestProcessor.getResult(" + config.getName()
          + ")#cache");
      cachedResult = getCachedResult(cacheKey);
      getResultCacheCase.stop();

      boolean up2date = compare(cachedResult, checkCacheResult);

      if (up2date) {
        collection = cachedResult;
      } else {
        UseCase getResultUncachedCase = MonitorFactory.startUseCase("CRRequestProcessor.getResult("
            + config.getName() + ")#uncached");
        result = ds.getResult(dsFilter, prefillAttributes, first, last, sorting);
        collection = toResolvableCollection(result);
        saveResult(cacheKey, collection);
        getResultUncachedCase.stop();
      }
    } catch (DatasourceException e) {
      logger.error("Cannot get the result from the Datasource.", e);
    }
    getResultCase.stop();
    return collection;
  }

  /**
   * Compares two resultsets for their updateTime.
   * @param left first Resolvable
   * @param right second Resolvable
   * @return returns false if they are not equal
   */
  public static boolean compare(final Collection<Resolvable> left, final Collection<Resolvable> right) {
    UseCase getResultVerifyCase = MonitorFactory.startUseCase("CRRequestProcessor.compare()#verify");
    if (left.size() != right.size()) {
      return false;
    } else {
      int leftUpdatetime = 0;
      for (Resolvable leftResolvable : left) {
        leftUpdatetime = checkUpdatetime(leftResolvable, leftUpdatetime);
      }
      int rightUpdatetime = 0;
      for (Resolvable rightResolvable : right) {
        rightUpdatetime = checkUpdatetime(rightResolvable, rightUpdatetime);
      }
      getResultVerifyCase.stop();
      if (rightUpdatetime != leftUpdatetime) {
        return false;
      }
    }
    return true;
  }

  /**
   * check if updatetime of resolvable is newer than given updatetime.
   * @param resolvable {@link Resolvable} to check the updatetime for.
   * @param updatetime timestamp.
   * @return newest updatetime, can be the updatetime of the resolvable or the
   * given updatetime
   */
  private static int checkUpdatetime(final Resolvable resolvable, final int updatetime) {
    Object updatetimestampObject = resolvable.get(UPDATEATTRIBUTE);
    if (updatetimestampObject instanceof Integer) {
      int updatetimestamp = ((Integer) updatetimestampObject).intValue();
      if (updatetimestamp > updatetime) {
        return updatetimestamp;
      }
    }
    return updatetime;
  }

  /**
   * get the result from the cache.
   * @param cacheKey key to get the result for
   * @return result for the cacheKey
   */
  private Collection<Resolvable> getCachedResult(final String cacheKey) {
    initCache();
    Object cacheResultObject = resultCache.get(cacheKey);
    if (cacheResultObject != null) {
      return toResolvableCollection(cacheResultObject);
    } else {
      return new Vector<Resolvable>(0);
    }
  }

  /**
   * save the result to the cache.
   * @param cacheKey key to store the result under
   * @param result result to cache
   */
  private void saveResult(final String cacheKey, final Collection<Resolvable> result) {
    initCache();
    try {
      resultCache.put(cacheKey, result);
    } catch (CacheException e) {
      logger.error("Cannot save the result in cache", e);
    }
  }

  /**
   * initialize the result cache.
   */
  private void initCache() {
    if (resultCache == null) {
      try {
        resultCache = JCS.getInstance("gentics-cr-CRRequestProcessor-results");
      } catch (CacheException e) {
        logger.error("Cannot initialize the result cache", e);
      }
    }
  }

  @Override
  public void finalize() {
    // TODO Auto-generated method stub
  }

}
TOP

Related Classes of com.gentics.cr.CachedCRRequestProcessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.