Package com.dotmarketing.viewtools.content.util

Source Code of com.dotmarketing.viewtools.content.util.ContentUtils

package com.dotmarketing.viewtools.content.util;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.dotcms.repackage.edu.emory.mathcs.backport.java.util.Collections;

import com.dotcms.content.elasticsearch.business.ESMappingAPIImpl;
import com.dotmarketing.beans.Identifier;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.common.model.ContentletSearch;
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.exception.DotSecurityException;
import com.dotmarketing.portlets.calendar.business.RecurrenceUtil;
import com.dotmarketing.portlets.contentlet.business.ContentletAPI;
import com.dotmarketing.portlets.contentlet.model.Contentlet;
import com.dotmarketing.portlets.structure.factories.RelationshipFactory;
import com.dotmarketing.portlets.structure.model.Relationship;
import com.dotmarketing.util.Logger;
import com.dotmarketing.util.PaginatedArrayList;
import com.dotmarketing.util.UtilMethods;
import com.dotmarketing.viewtools.content.PaginatedContentList;
import com.liferay.portal.model.User;

/**
* The purpose of this class is to abstract the methods called from the ContentTool Viewtool
* so they can be called from other viewtools or external plugins.
* other viewtools can return a ContentMap back to the page
* @author Jason Tesser
* @since 1.9.3
*/

public class ContentUtils {
 
     private static ContentletAPI conAPI;
     public static final ContentUtils INSTANCE = new ContentUtils();

      private ContentUtils() {
        conAPI = APILocator.getContentletAPI();
      }

      public ContentUtils getInstance()
      {
          return INSTANCE;
      }

    /**
     * Will pull a single piece of content for you based on the inode or identifier. It will always
     * try to retrieve the live content unless in EDIT_MODE in the backend of dotCMS when passing in an
     * identifier.  If it is an inode this is ignored.
     * Will return NULL if not found
     * @param inodeOrIdentifier Can be either an Inode or Indentifier of content.
     * @return NULL if not found
     */
    public static Contentlet find(String inodeOrIdentifier, User user, boolean EDIT_OR_PREVIEW_MODE, long sessionLang){
      return find(inodeOrIdentifier,user,null,EDIT_OR_PREVIEW_MODE, sessionLang);
    }

     
      public static Contentlet find(String inodeOrIdentifier, User user, String tmDate, boolean EDIT_OR_PREVIEW_MODE, long sessionLang){
      String[] recDates = null;
      try {
        recDates = RecurrenceUtil.getRecurrenceDates(inodeOrIdentifier);
        inodeOrIdentifier = RecurrenceUtil.getBaseEventIdentifier(inodeOrIdentifier);
        Contentlet c = conAPI.find(inodeOrIdentifier, user, true);
        if(c != null){
          if(c.getStructure().getVelocityVarName().equals("calendarEvent")
              && (recDates!=null && recDates.length==2)){
            String startDate = recDates[0];
            String endDate = recDates[1];
            if(UtilMethods.isSet(startDate) && UtilMethods.isSet(endDate)){
              c.setDateProperty("startDate", new Date(Long.parseLong(startDate)));
              c.setDateProperty("endDate", new Date(Long.parseLong(endDate)));
            }
          }
          return c;
        }
      } catch (Exception e) {
        Logger.error(ContentUtils.class,e.getMessage(),e);
        return null;
      }
     
      try {
     
          List<Contentlet> l=null;
          if(tmDate!=null) {                     
              // timemachine future dates
              Date ffdate=new Date(Long.parseLong(tmDate));
              Identifier ident=APILocator.getIdentifierAPI().find(inodeOrIdentifier);
              if(ident==null || !UtilMethods.isSet(ident.getId())) return null;
              boolean showlive=true;
              if(UtilMethods.isSet(ident.getSysExpireDate()) && ffdate.after(ident.getSysExpireDate()))
                  return null; // it has expired. return nothing
              if(UtilMethods.isSet(ident.getSysPublishDate()) && ffdate.after(ident.getSysPublishDate()))
                  showlive=false; // it would be published. show the working
              l = conAPI.search("+identifier:" + inodeOrIdentifier +
                      " +deleted:false " + (showlive ? "+live:true" : "+working:true"), 0, -1, "modDate", user, true);
          }
          else {
             String stateQuery = EDIT_OR_PREVIEW_MODE ? "+working:true +deleted:false" : "+live:true +deleted:false";
             l = conAPI.search("+identifier:" + inodeOrIdentifier + " " + stateQuery, 0, -1, "modDate", user, true);
          }
     
       
        if(l== null || l.size() < 1){
          return null;
        }else{
          if(l.size()>1){
            Logger.warn(ContentUtils.class, "More then one live or working content found with identifier = " + inodeOrIdentifier);
           
            //If the list of contentlest with the same identifier is > 1
            //try to search if there is one with the same language id.
            for (Contentlet contentlet : l){
              if(contentlet.getLanguageId() == sessionLang)
                return contentlet;
            }
          }
          if(l.get(0).getStructure().getVelocityVarName().equals("calendarEvent")
              && (recDates!=null && recDates.length==2)){
            String startDate = recDates[0];
            String endDate = recDates[1];
            if(UtilMethods.isSet(startDate) && UtilMethods.isSet(endDate)){
              l.get(0).setDateProperty("startDate", new Date(Long.parseLong(startDate)));
              l.get(0).setDateProperty("endDate", new Date(Long.parseLong(endDate)));
            }
          }
          //If anything else match, return the firs result.
          return (Contentlet) l.get(0);
        }
      } catch (Exception e) {
        Logger.error(ContentUtils.class,e.getMessage());
        Logger.debug(ContentUtils.class,e.getMessage(),e);
        return null;
      }
    }
   
    /**
     * Returns empty List if no results are found
     * @param query - Lucene Query used to search for content - Will append live, working, deleted, and language if not passed
     * @param limit 0 is the dotCMS max limit which is 10000. Becareful when searching for unlimited amount as all content will load into memory
     * @param sort - Velocity variable name to sort by.  this is a string and can contain multiple values "sort1 acs, sort2 desc"
     * @return  Returns empty List if no results are found
     */
    public static List<Contentlet> pull(String query, String limit, String sort,User user, String tmDate){
        int l = new Integer(limit);
        return pull(query, l, sort, user, tmDate);
    }
   
    /**
     * Returns empty List if no results are found
     * @param query - Lucene Query used to search for content - Will append live, working, deleted, and language if not passed
     * @param limit 0 is the dotCMS max limit which is 10000. Becareful when searching for unlimited amount as all content will load into memory
     * @param sort - Velocity variable name to sort by.  this is a string and can contain multiple values "sort1 acs, sort2 desc"
     * @return Returns empty List if no results are found
     */
    public static List<Contentlet> pull(String query,int limit, String sort, User user, String tmDate){
        return pull(query,-1,limit,sort, user, tmDate);
    }
   
    public static PaginatedArrayList<Contentlet> pull(String query, int offset,int limit, String sort, User user, String tmDate){
        PaginatedArrayList<Contentlet> ret = new PaginatedArrayList<Contentlet>();
      try {
        //need to send the query with the defaults ---
          List<Contentlet> contentlets=null;
          if(tmDate!=null && query.contains("+live:true")) {
              // with timemachine on!
                String datestr=tmDate;
                Date futureDate=new Date(Long.parseLong(datestr));
                query=query.replaceAll("\\+live\\:true", "").replaceAll("\\+working\\:true", "");
                String ffdate=ESMappingAPIImpl.datetimeFormat.format(futureDate);
               
                String notexpired=" +expdate:["+ffdate+" TO 29990101000000] ";
                String wquery=query + " +working:true " +
                    "+pubdate:["+ESMappingAPIImpl.datetimeFormat.format(new Date())+
                        " TO "+ffdate+"] "+notexpired;
                String lquery=query + " +live:true " + notexpired;
               
                PaginatedArrayList<Contentlet> wc=(PaginatedArrayList<Contentlet>)conAPI.search(wquery, limit, offset, sort, user, true);
                PaginatedArrayList<Contentlet> lc=(PaginatedArrayList<Contentlet>)conAPI.search(lquery, limit, offset, sort, user, true);
               
                // merging both results avoiding repeated inodes
                Set<String> inodes=new HashSet<String>();
                contentlets=new ArrayList<Contentlet>();
                ret.setTotalResults(
                        wc.getTotalResults()>lc.getTotalResults() ?
                                wc.getTotalResults() : lc.getTotalResults());
                contentlets.addAll(wc);
                for(Contentlet cc : wc)
                    inodes.add(cc.getInode());
                for(Contentlet cc : lc) {
                    if(!inodes.contains(cc.getInode())) {
                        contentlets.add(cc);
                        inodes.add(cc.getInode());
                    }
                }
               
                // sorting the result
                if(UtilMethods.isSet(sort) && !sort.trim().equals("random")) {
                    final String[] sorts=sort.split(",");
                    Collections.sort(contentlets, new Comparator<Contentlet>() {
                        @SuppressWarnings({"unchecked","rawtypes"})
                          @Override
                        public int compare(Contentlet a, Contentlet b) {
                            int comp=0;
                            for(int x=0;x<sorts.length && comp==0;x++) {
                                String[] ss=sorts[x].split(" ");
                                Comparable c1=(Comparable)a.get(ss[0]);
                                Comparable c2=(Comparable)b.get(ss[0]);
                                if(c1!=null && c2!=null) {
                                    if(ss.length==1 || ss[1].equals("asc"))
                                        comp=c1.compareTo(c2);
                                    else
                                        comp=c2.compareTo(c1);
                                }
                            }  
                            return comp;
                        }
                    });
                }
               
                // truncate to respect limit
                if(contentlets.size()>limit)
                    contentlets=contentlets.subList(0, limit);
          }
          else {
              // normal query
              PaginatedArrayList<Contentlet> conts=(PaginatedArrayList<Contentlet>)conAPI.search(query, limit, offset, sort, user, true);
              ret.setTotalResults(conts.getTotalResults());
              contentlets=conts;
          }
        for(Contentlet c : contentlets)
          ret.add(c);
      } catch (Exception e) {
        Logger.error(ContentUtils.class,e.getMessage());
        Logger.debug(ContentUtils.class,e.getMessage(),e);
      }
     
      return ret;
    }
   
    /**
     * Will return a ContentMap object which can be used on dotCMS front end.
     * This method is better then the old #pullcontent macro because it doesn't have to
     * parse all the velocity content object that are returned.  If you are building large pulls
     * and depending on the types of fields on the content this can get expensive especially
     * with large data sets.<br />
     * EXAMPLE:<br />
     * #foreach($con in $dotcontent.pullPagenated('+structureName:newsItem',20,20,'modDate desc'))<br />
     *     $con.headline<br />
     * #end<br />
     * Returns empty List if no results are found <br />
     * there is a totalResults avialible to you on the returned list. $retList.totalResults
     * @param query - Lucene Query used to search for content - Will append live, working, deleted, and language if not passed
     * @param limit 0 is the dotCMS max limit which is 10000. Becareful when searching for unlimited amount as all content will load into memory
     * @param offset offset to start the results from
     * @param sort - Velocity variable name to sort by.  this is a string and can contain multiple values "sort1 acs, sort2 desc"
     * @return Returns empty List if no results are found
     */
    public static PaginatedArrayList<Contentlet> pullPagenated(String query, int limit, int offset, String sort,User user, String tmDate){
      return pull(query, offset, limit, sort, user, tmDate);
    }
   
    /**
     * Works just similar to the pullPagenated. Will return a ContentMap object which can be used on dotCMS front end.
     * This method is better then the old #pullcontent macro because it doesn't have to
     * parse all the velocity content object that are returned.  If you are building large pulls
     * and depending on the types of fields on the content this can get expensive especially
     * with large data sets.<br />
     * EXAMPLE:<br />
     * #set($pagedList = $dotcontent.pullPerPage("+structureName:webPageContent" ,20, 3, "modDate desc"))<br/>
     * <div><br/>
     *     $pagedList<br/>
     * </div><br/>
     * <h2>$pagedList.previousPage</h2><br/>
     * <h2>$pagedList.nextPage</h2><br/>
     * <h2>$pagedList.totalPages</h2><br/>
     * <h2>$pagedList.totalResults</h2><br/>
     * #foreach($con in $pagedList)<br/>
     *     <h2>$con.inode</h2><br/>
     *     <h2>$con.identifier</h2><br/>
     *     $con.title<br/>
     * #end<br />
     * Returns empty List if no results are found
     * The returned list is a PaginatedContentList which lets you get at the totalPages, nextPage, and previousPage, and totalResults as helpers ie.. $conlist.previousPage ...
     * @param query - Lucene Query used to search for content - Will append live, working, deleted, and language if not passed
     * @param currentPage Current page number for pagination the first page would be one.
     * @param contentsPerPage Number of contentlets you are displaying per page
     * @param offset offset to start the results from
     * @param sort - Velocity variable name to sort by.  this is a string and can contain multiple values "sort1 acs, sort2 desc"
     * @return Returns empty List if no results are found
     *
     */
    public static PaginatedContentList<Contentlet> pullPerPage(String query, int currentPage, int contentsPerPage, String sort, User user, String tmDate){
      PaginatedArrayList<Contentlet> cmaps = pullPagenated(query, contentsPerPage, contentsPerPage * (currentPage - 1), sort, user, tmDate);
      PaginatedContentList<Contentlet> ret = new PaginatedContentList<Contentlet>();
     
      if(cmaps.size()>0){
        long minIndex = (currentPage - 1) * contentsPerPage;
            long totalCount = cmaps.getTotalResults();
            long maxIndex = contentsPerPage * currentPage;
            if((minIndex + contentsPerPage) >= totalCount){
              maxIndex = totalCount;
            }
        ret.addAll(cmaps);
        ret.setTotalResults(cmaps.getTotalResults());
        ret.setTotalPages((long)Math.ceil(((double)cmaps.getTotalResults())/((double)contentsPerPage)));
        ret.setNextPage(maxIndex < totalCount);
        ret.setPreviousPage(minIndex > 0);
        cmaps = null;
      }
      return ret;
    }
   
    /**
     * Will return a ContentSearch object which can be used on dotCMS front end.
     * The method can be used to determine the inodes or identifiers which match a given query.
     * It does NOT return actual content only the inodes and identifiers.  An example use could be 
     * you need to know if a query matches at all. Lets say you want to know if a category is used at all within
     * a given query this is the fastest way to figure it out as dotCMS doesn't have to put together the content itself.
     * @param query - Lucene Query used to search for content - Will append live, working, deleted, and language if not passed
     * @param limit 0 is the dotCMS max limit which is 10000.
     * @return
     */
    public static List<ContentletSearch> query(String query, int limit, User user, String tmDate){
      return query(query, limit, "modDate", user, tmDate);
    }
   
    /**
     * Will return a ContentSearch object which can be used on dotCMS front end.
     * The method can be used to determine the inodes or identifiers which match a given query.
     * It does NOT return actual content only the inodes and identifiers.  An example use could be 
     * you need to know if a query matches at all. Lets say you want to know if a category is used at all within
     * a given query this is the fastest way to figure it out as dotCMS doesn't have to put together the content itself.
     * Returns empty List if no results are found
     * @param query - Lucene Query used to search for content - Will append live, working, deleted, and language if not passed
     * @param limit 0 is the dotCMS max limit which is 10000.
     * @param sort - Velocity variable name to sort by.  this is a string and can contain multiple values "sort1 acs, sort2 desc"
     * @return Returns empty List if no results are found
     */
    public static List<ContentletSearch> query(String query, int limit, String sort, User user, String tmDate){
      List<ContentletSearch> ret = null;
      try {
              if(tmDate!=null && query.contains("+live:true")) {
                  // with timemachine on!
                  // as we need to load contentlets anyway to sort
                  // lets just call pull here
                  List<Contentlet> conts=pull(query, limit, sort, user, tmDate);
                  ret = new ArrayList<ContentletSearch>(conts.size());
                  for(Contentlet cm : conts) {
                      ContentletSearch cs=new ContentletSearch();
                      cs.setInode((String)cm.get("inode"));
                      cs.setIdentifier((String)cm.get("identifier"));
                      ret.add(cs);
                  }  
              }
              else {
                  // normal query
                  ret = conAPI.searchIndex(query, limit, -1, sort, user, true);
              }
      } catch (Exception e) {
        Logger.error(ContentUtils.class,e.getMessage(),e);
      }
      if(ret == null){
        ret = new ArrayList<ContentletSearch>();
      }
      return ret;
    }
   
    /**
     * Use this method to return the number of contents which match a particular query.
     * @param query - Lucene Query used to search for content - Will append live, working, deleted, and language if not passed
     * @return
     */
    public static long count(String query, User user, String tmDate) {
      try {
          if(tmDate!=null && query.contains("+live:true"))
              return query(query,0, user, tmDate).size();
          else
              return conAPI.indexCount(query, user, true);
          } catch (Exception e) {
              Logger.error(ContentUtils.class, "can't get indexCount for query: "+query,e);
              return 0;
          }
    }
   
    /**
     * Will return a ContentMap object which can be used on dotCMS front end.
     * This method is better then the old #pullRelatedContent macro because it doesn't have to
     * parse all the velocity content object that are returned.  If you are building large pulls
     * and depending on the types of fields on the content this can get expensive especially
     * with large data sets.<br />
     * EXAMPLE:<br />
     * #foreach($con in $dotcontent.pullRelated('myRelationship','asbd-asd-asda-asd',false,5))<br />
     *     $con.title<br />
     * #end<br />
     * The method will figure out language, working and live for you.
     * Returns empty List if no results are found
     * @param relationshipName - Name of the relationship as defined in the structure.
     * @param contentletIdentifier - Identifier of the contentlet
     * @param pullParents Should the related pull be based on Parents or Children
     * @param limit 0 is the dotCMS max limit which is 10000. Becareful when searching for unlimited amount as all content will load into memory
     * @return Returns empty List if no results are found
     * @throws DotSecurityException
     * @throws DotDataException
     */
    public static List<Contentlet> pullRelated(String relationshipName, String contentletIdentifier, boolean pullParents, int limit, User user, String tmDate) {
      return pullRelated(relationshipName, contentletIdentifier, null, pullParents, limit, null, user, tmDate);
    }
   
    /**
     * Will return a ContentMap object which can be used on dotCMS front end.
     * This method is better then the old #pullRelatedContent macro because it doesn't have to
     * parse all the velocity content object that are returned.  If you are building large pulls
     * and depending on the types of fields on the content this can get expensive especially
     * with large data sets.<br />
     * EXAMPLE:<br />
     * #foreach($con in $dotcontent.pullRelated('myRelationship','asbd-asd-asda-asd',false,5,'modDate'))<br />
     *     $con.title<br />
     * #end<br />
     * The method will figure out language, working and live for you.
     * Returns empty List if no results are found
     * @param relationshipName - Name of the relationship as defined in the structure.
     * @param contentletIdentifier - Identifier of the contentlet
     * @param pullParents Should the related pull be based on Parents or Children
     * @param limit 0 is the dotCMS max limit which is 10000. Becareful when searching for unlimited amount as all content will load into memory
     * @param sort - Velocity variable name to sort by.  this is a string and can contain multiple values "sort1 acs, sort2 desc". Can be Null
     * @return Returns empty List if no results are found
     * @throws DotSecurityException
     * @throws DotDataException
     */
    public static List<Contentlet> pullRelated(String relationshipName, String contentletIdentifier, boolean pullParents, int limit, String sort, User user, String tmDate) {
      return pullRelated(relationshipName, contentletIdentifier, null, pullParents, limit, sort, user, tmDate);
    }
   
    /**
     * Will return a ContentMap object which can be used on dotCMS front end.
     * This method is better then the old #pullRelatedContent macro because it doesn't have to
     * parse all the velocity content object that are returned.  If you are building large pulls
     * and depending on the types of fields on the content this can get expensive especially
     * with large data sets.<br />
     * EXAMPLE:<br />
     * #foreach($con in $dotcontent.pullRelated('myRelationship','asbd-asd-asda-asd','+myField:someValue',false,5,'modDate desc'))<br />
     *     $con.title<br />
     * #end<br />
     * The method will figure out language, working and live for you if not passed in with the condition
     * Returns empty List if no results are found
     * @param relationshipName - Name of the relationship as defined in the structure.
     * @param contentletIdentifier - Identifier of the contentlet
     * @param condition - Extra conditions to add to the query. like +title:Some Title.  Can be Null
     * @param pullParents Should the related pull be based on Parents or Children
     * @param limit 0 is the dotCMS max limit which is 10000. Becareful when searching for unlimited amount as all content will load into memory
     * @param sort - Velocity variable name to sort by.  this is a string and can contain multiple values "sort1 acs, sort2 desc". Can be Null
     * @return Returns empty List if no results are found
     * @throws DotSecurityException
     * @throws DotDataException
     * @return Returns empty List if no results are found
     */
    public static List<Contentlet> pullRelated(String relationshipName, String contentletIdentifier, String condition, boolean pullParents, int limit, String sort, User user, String tmDate) { 
      Relationship rel = RelationshipFactory.getRelationshipByRelationTypeValue(relationshipName);
      String relNameForQuery = "";
      if(rel.getParentStructureInode().equals(rel.getChildStructureInode())){
        if(pullParents){
          relNameForQuery = relationshipName.trim() + "-child";
        }else{
          relNameForQuery = relationshipName.trim() + "-parent";
        }
      }
     
      if(!UtilMethods.isSet(relNameForQuery))//DOTCMS-5328
        relNameForQuery = rel.getRelationTypeValue();
     
      contentletIdentifier = RecurrenceUtil.getBaseEventIdentifier(contentletIdentifier);
     
           
      String pullquery = "+type:content +" + relNameForQuery + ":" + contentletIdentifier;
         
      if(UtilMethods.isSet(condition)){
               pullquery += " " + condition;
      }

      if(!UtilMethods.isSet(sort)){
        sort = relationshipName + "-" + contentletIdentifier + "-order";
      }
      return pull(pullquery, limit, sort, user, tmDate);
    }
   
}
TOP

Related Classes of com.dotmarketing.viewtools.content.util.ContentUtils

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.