Package com.gentics.cr.plink

Source Code of com.gentics.cr.plink.PathResolver

package com.gentics.cr.plink;

import java.util.Collection;
import java.util.Iterator;

import javax.servlet.http.HttpServletRequest;

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.DatasourceNotAvailableException;
import com.gentics.api.lib.exception.ParserException;
import com.gentics.api.lib.expressionparser.Expression;
import com.gentics.api.lib.expressionparser.ExpressionParser;
import com.gentics.api.lib.expressionparser.ExpressionParserException;
import com.gentics.api.lib.expressionparser.filtergenerator.DatasourceFilter;
import com.gentics.api.lib.expressionparser.filtergenerator.FilterGeneratorException;
import com.gentics.api.lib.resolving.Resolvable;
import com.gentics.api.portalnode.connector.PortalConnectorFactory;
import com.gentics.cr.CRConfig;
import com.gentics.cr.CRDatabaseFactory;
import com.gentics.cr.CRRequest;
import com.gentics.cr.CRResolvableBean;

/**
* This class is used to resolve URLs to objects an vice versa.
*
*
* Last changed: $Date: 2010-03-31 16:14:26 +0200 (Mi, 31 Mär 2010) $
* @version $Revision: 522 $
* @author $Author: supnig@constantinopel.at $
*
*/
public class PathResolver {

  private CRConfig conf = null;
  private String appRule = null;

  private Expression expression = null;

  private static Logger log = Logger.getLogger(PathResolver.class);

  private static final String rule = "object.filename == data.filename && (object.folder_id.pub_dir == data.path || object.folder_id.pub_dir == concat(data.path, '/'))";
  private static final String fast_rule = "object.filename == data.filename && (object.pub_dir == data.path || object.pub_dir == concat(data.path, '/'))";
  private static final String[] prefillAttributes = new String[] { "filename", "pub_dir", "folder_id" };
  private static final String[] fastprefillAttributes = new String[] { "filename", "pub_dir" };

  private boolean fast = false;

  /**
   * Initialize the expression needed to resolve Objects from passed URLs. As
   * this uses a lot of time initalization in the constructor improves
   * performance. Initialize PathResolver once on Server startup.
   * @param conf
   * @param appRule
   *
   */
  public PathResolver(CRConfig conf, String appRule) {

    this.conf = conf;
    this.appRule = appRule;

    initRule(rule);

  }

  /**
   * Initialize the expression needed to resolve Objects from passed URLs. As
   * this uses a lot of time initalization in the constructor improves
   * performance. Initialize PathResolver once on Server startup.
   * @param conf
   * @param appRule
   * @param usefastrule if this is set to true, the PathResolver will from now on use a much simpler rule to acquire the objects
   *               it is required that the pub_dir is published with each page to use this rule
   */
  public PathResolver(CRConfig conf, String appRule, boolean usefastrule) {

    this.conf = conf;
    this.appRule = appRule;

    if (usefastrule) {
      initRule(fast_rule);
      fast = true;
    } else {
      initRule(rule);
      fast = false;
    }

  }

  private void initRule(String r) {
    // define the rule for finding pages or files with path/filename
    //Apply AppRule
    if (appRule != null && !appRule.equals("")) {
      r = "(" + r + ") AND " + appRule;
    }
    // parse the rule into an expression object (check for syntax
    // errors)
    try {
      this.expression = ExpressionParser.getInstance().parse(r);
    } catch (Exception e) {
      log.error("Could create expression path rule.");
    }
  }

  /**
   * This method has to be called right after the constructor.
   *
   * It prefetches all objects with their contentids and pubdirs and paths.
   *
   * @param cacheWarmRule - Rule that is used to fetch the objects
   */
  @SuppressWarnings("unchecked")
  public void warmCache(final String cacheWarmRule) {

    Datasource ds = null;
    try {

      // prepare the filter
      ds = this.conf.getDatasource();
      DatasourceFilter filter = ds.createDatasourceFilter(ExpressionParser.getInstance().parse(cacheWarmRule));

      // use the filter to get matching objects
      String[] atts = null;
      if (fast) {
        atts = fastprefillAttributes;
      } else {
        atts = prefillAttributes;
      }
      Collection<Resolvable> coll = (Collection<Resolvable>) ds.getResult(filter, atts);
      for (Resolvable res : coll) {
        CRRequest req = new CRRequest();
        req.setUrl((String) res.get("pub_dir") + (String) res.get("filename"));
        this.getObject(req);
      }

    } catch (FilterGeneratorException e) {
      log.error("Could not create filter with cacheWarmRule (" + cacheWarmRule + ") expression.");
    } catch (ExpressionParserException e) {
      log.error("Error while parsing path expression (" + cacheWarmRule + ").");
    } catch (DatasourceException e) {
      log.error("Error while prefetching objects with rule (" + cacheWarmRule + ").");
    } catch (ParserException e) {
      log.error("Could not create filter with cacheWarmRule (" + cacheWarmRule + ") expression.");
    } finally {
      CRDatabaseFactory.releaseDatasource(ds);
    }

  }

  /**
   * The Method looks in the repository with the expression initialized in the
   * constructor and tries to find a corresponding object. This only works
   * correctly when only one node is in the repository, otherwise there may
   * bee more object with the same URL in the repository.
   * @param request
   * @return a Resolvable Object based on the passed URL.
   */
  @SuppressWarnings("unchecked")
  public CRResolvableBean getObject(final CRRequest request) {
    Resolvable contentObject = null;
    String url = request.getUrl();
    Datasource ds = null;
    if (url != null) {
      try {

        // prepare the filter
        ds = this.conf.getDatasource();
        DatasourceFilter filter = ds.createDatasourceFilter(expression);

        //Deploy base objects
        Iterator<String> it = request.getObjectsToDeploy().keySet().iterator();
        while (it.hasNext()) {
          String key = it.next();
          filter.addBaseResolvable(key, request.getObjectsToDeploy().get(key));
        }

        // add the data to the filter
        filter.addBaseResolvable("data", new PathBean(url));

        // use the filter to get matching objects
        Collection<Resolvable> objects = ds.getResult(filter, request.getAttributeArray());

        Iterator<Resolvable> i = objects.iterator();
        if (i.hasNext()) {
          // we found at least one object, take the first one
          contentObject = i.next();
        }

      } catch (FilterGeneratorException e) {
        log.error("Could not create filter with path expression.");
      } catch (ExpressionParserException e) {
        log.error("Error while parsing path expression.");
      } catch (DatasourceException e) {
        log.error("Datasource error while getting object for url " + url);
      } finally {
        CRDatabaseFactory.releaseDatasource(ds);
      }
    }
    CRResolvableBean ret = null;
    if (contentObject != null) {
      ret = new CRResolvableBean(contentObject, new String[] {});
    }
    return ret;
  }

  /**
   * initializes a Resolvable Object an calls getPath(Resolvable linkedObject).
   * {@link com.gentics.cr.plink.PathResolver#getPath(Resolvable)}
   *
   * @param contentid
   */
  public String getPath(final String contentid) {

    Resolvable linkedObject = null;
    Datasource ds = null;
    try {
      ds = this.conf.getDatasource();
      // initialize linked Object
      linkedObject = PortalConnectorFactory.getContentObject(contentid, ds);
      return getPath(linkedObject);

    } catch (DatasourceNotAvailableException e) {
      log.error("Datasource error generating url for " + contentid);
    } finally {
      CRDatabaseFactory.releaseDatasource(ds);
    }

    // if the linked Object cannot be initialized return a dynamic URL
    //    this.log.info("Use dynamic url for " + contentid);
    //    return getDynamicUrl(contentid);
    return (null);
  }

  /**
   * @param linkedObject
   *            must be a Resolvable
   * @return a the URL from Gentics Content.Node. This expects the attributes
   *         filename and folder_id to be set for the passed object and the
   *         attribute pub_dir to be set for folders.
   */
  public String getPath(Resolvable linkedObject) {

    String filename = "";
    String pub_dir = "";

    if (linkedObject != null) {

      // get filename from linkedObject
      filename = (String) linkedObject.get("filename");

      // Get folder Object from attribute folder_id and attribute pub_dir
      // from it
      Resolvable folder = (Resolvable) linkedObject.get("folder_id");
      if (folder != null) {
        pub_dir = (String) folder.get("pub_dir");
      }
    }

    // If filename is empty or not set, no need to return an path
    if (filename != null && !"".equals(filename)) {
      return pub_dir + filename;
    } else {
      // no filename or path could be resolved
      // return a dynamic URL instead
      if (linkedObject != null && linkedObject.get("contentid") != null) {
        log.warn("Object " + linkedObject.get("contentid") + " has no filename.");
        return getDynamicUrl((String) linkedObject.get("contentid"));
      } else {
        log.warn("Contentid of linkObject could not be resolved " + "therefore no filename can be looked up");
        if (linkedObject != null) {
          log.debug("The resolvable (linkObject) provides the following information: " + linkedObject);
        }
        return null;
      }
    }
  }

  /**
   * @param contentid
   * @return a dynamic URL to suitable for CRServlet.
   */
  public String getDynamicUrl(final String contentid) {
    return "?contentid=" + contentid;
  }

  /**
   * Get the alternate URL for the request. This is used if the object cannot be resolved dynamically.
   * @param contentid String with the identifier of the object
   * @return String with the configured servlet / portal url.
   */
  public String getAlternateUrl(String contentid) {
    String url = null;
    String obj_type = contentid.split("\\.")[0];
    if (obj_type != null) {
      //try to get a specific URL for the objecttype
      url = conf.getString(CRConfig.ADVPLR_HOST + "." + obj_type);
    }
    if (url == null) {
      //if we didn't get a specific URL take the generic one
      url = conf.getString(CRConfig.ADVPLR_HOST);
    }
    return url + contentid;
  }

  /**
   * @param contentid
   * @param config
   * @param request
   * @return a dynamic URL to suitable for CRServlet.
   * Supports beautiful URLs, therefore it needs to load DB Objects and Attributes
   */
  public String getDynamicUrl(String contentid, CRConfig config, CRRequest request) {
    String url = null;
    if (request != null) {
      url = (String) request.get("url");
      if (url == null)
        return getDynamicUrl(contentid);
      else {
        Datasource ds = null;
        String ret = null;
        try {
          //if there is an attribute URL the servlet was called with a beautiful URL so give back a beautiful URL         
          //check if valid local link
          String applicationrule = (String) config.get("applicationrule");
          ds = config.getDatasource();
          Expression expression = null;
          try {
            expression = PortalConnectorFactory.createExpression("object.contentid == '" + contentid
                + "' && " + applicationrule);
          } catch (ParserException exception) {
            log.error("Error while building expression object for " + contentid, exception);
            System.out.println("Error while building expression object for " + contentid);
            ret = getDynamicUrl(contentid);
          }

          DatasourceFilter filter = null;
          try {
            filter = ds.createDatasourceFilter(expression);
          } catch (ExpressionParserException e) {
            log.error("Error while building filter object for " + contentid, e);
            ret = getDynamicUrl(contentid);
          }
          int count = 0;
          try {
            count = ds.getCount(filter);
          } catch (DatasourceException e) {
            log.error("Error while querying for " + contentid, e);
            ret = getDynamicUrl(contentid);
          }

          if (count == 0 || "true".equals(config.getString(CRConfig.ADVPLR_HOST_FORCE))) { //not permitted or forced, build link
            ret = getAlternateUrl(contentid);
          } else {

            Resolvable plinkObject;
            try {

              plinkObject = PortalConnectorFactory.getContentObject(contentid, ds);
              //TODO: make this more beautiful and compatible with portlets
              String filename_attribute = (String) config.get(CRConfig.ADVPLR_FN_KEY);
              String pub_dir_attribute = (String) config.get(CRConfig.ADVPLR_PB_KEY);
              String filename = (String) plinkObject.get(filename_attribute);
              String pub_dir = (String) plinkObject.get(pub_dir_attribute);
              HttpServletRequest servletRequest = (HttpServletRequest) request.get("request");
              String contextPath = servletRequest.getContextPath();
              String servletPath = servletRequest.getServletPath();
              ret = contextPath + servletPath + pub_dir + filename;
            } catch (DatasourceNotAvailableException e) {
              log.error("Error while getting object for " + contentid, e);
              ret = getDynamicUrl(contentid);
            }
          }
        } catch (Exception e) {
          log.error("Error while processing dynamic url", e);
        } finally {
          CRDatabaseFactory.releaseDatasource(ds);
        }
        return ret;
      }
    } else {
      return getAlternateUrl(contentid);
    }

  }

}
TOP

Related Classes of com.gentics.cr.plink.PathResolver

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.