svn commit: r1102554 [1/2] - in /ofbiz/trunk/applications/content: entitydef/ script/org/ofbiz/content/content/ servicedef/ src/org/ofbiz/content/content/

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r1102554 [1/2] - in /ofbiz/trunk/applications/content: entitydef/ script/org/ofbiz/content/content/ servicedef/ src/org/ofbiz/content/content/

hansbak-2
Author: hansbak
Date: Fri May 13 03:20:58 2011
New Revision: 1102554

URL: http://svn.apache.org/viewvc?rev=1102554&view=rev
Log:
add a keyword search function to the content component

Added:
    ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentKeywordIndex.java   (with props)
    ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearch.java   (with props)
    ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearchEvents.java   (with props)
    ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearchSession.java   (with props)
Modified:
    ofbiz/trunk/applications/content/entitydef/eecas.xml
    ofbiz/trunk/applications/content/entitydef/entitymodel.xml
    ofbiz/trunk/applications/content/script/org/ofbiz/content/content/ContentServices.xml
    ofbiz/trunk/applications/content/servicedef/services.xml

Modified: ofbiz/trunk/applications/content/entitydef/eecas.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/entitydef/eecas.xml?rev=1102554&r1=1102553&r2=1102554&view=diff
==============================================================================
--- ofbiz/trunk/applications/content/entitydef/eecas.xml (original)
+++ ofbiz/trunk/applications/content/entitydef/eecas.xml Fri May 13 03:20:58 2011
@@ -26,4 +26,36 @@ under the License.
         <action service="clearAssociatedRenderCache" mode="sync" />
     </eca>
 
+    <!-- Content Keyword Indexing ECAs -->
+    <eca entity="Content" operation="create" event="return">
+        <action service="indexContentKeywords" mode="sync" value-attr="contentInstance"/>
+    </eca>
+    <eca entity="Content" operation="store" event="return">
+        <action service="indexContentKeywords" mode="sync"/>
+    </eca>
+    <eca entity="ContentAttribute" operation="create-store" event="return">
+        <action service="indexContentKeywords" mode="sync"/>
+    </eca>
+    <eca entity="ContentMetaData" operation="create-store" event="return">
+        <action service="indexContentKeywords" mode="sync"/>
+    </eca>
+    <eca entity="ContentRole" operation="create-store" event="return">
+        <action service="indexContentKeywords" mode="sync"/>
+    </eca>
+    <eca entity="ProductContent" operation="create-store" event="return">
+        <action service="indexContentKeywords" mode="sync"/>
+    </eca>
+    <eca entity="ProductCategoryContent" operation="create-store" event="return">
+        <action service="indexContentKeywords" mode="sync"/>
+    </eca>
+    <eca entity="PartyContent" operation="create-store" event="return">
+        <action service="indexContentKeywords" mode="sync"/>
+    </eca>
+    <eca entity="WebSiteContent  " operation="create-store" event="return">
+        <action service="indexContentKeywords" mode="sync"/>
+    </eca>
+    <eca entity="WorkEffortContent  " operation="create-store" event="return">
+        <action service="indexContentKeywords" mode="sync"/>
+    </eca>
+
 </entity-eca>

Modified: ofbiz/trunk/applications/content/entitydef/entitymodel.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/entitydef/entitymodel.xml?rev=1102554&r1=1102553&r2=1102554&view=diff
==============================================================================
--- ofbiz/trunk/applications/content/entitydef/entitymodel.xml (original)
+++ ofbiz/trunk/applications/content/entitydef/entitymodel.xml Fri May 13 03:20:58 2011
@@ -1644,4 +1644,52 @@ under the License.
             <key-map field-name="helpContentId" rel-field-name="contentId"/>
         </relation>
     </extend-entity>
+    
+    <entity entity-name="ContentKeyword" package-name="org.ofbiz.content.content" title="Content Keyword Entity" never-cache="true">
+      <field name="contentId" type="id-ne"></field>
+      <field name="keyword" type="short-varchar"></field>
+      <field name="relevancyWeight" type="numeric"></field>
+      <prim-key field="contentId"/>
+      <prim-key field="keyword"/>
+      <relation type="one" fk-name="CNT_KWD_CNT" rel-entity-name="Content">
+        <key-map field-name="contentId"/>
+      </relation>
+      <index name="CNT_KWD_KWD">
+        <index-field name="keyword"/>
+      </index>
+    </entity>
+    <entity entity-name="ContentSearchConstraint" package-name="org.ofbiz.content.content" never-cache="true" title="Content Search Result Constraint Entity">
+      <field name="contentSearchResultId" type="id-ne"></field>
+      <field name="constraintSeqId" type="id-ne"></field>
+      <field name="constraintName" type="long-varchar"></field>
+      <field name="infoString" type="long-varchar"></field>
+      <field name="includeSubCategories" type="indicator"></field>
+      <field name="isAnd" type="indicator"></field>
+      <field name="anyPrefix" type="indicator"></field>
+      <field name="anySuffix" type="indicator"></field>
+      <field name="removeStems" type="indicator"></field>
+      <field name="lowValue" type="short-varchar"></field>
+      <field name="highValue" type="short-varchar"></field>
+      <prim-key field="contentSearchResultId"/>
+      <prim-key field="constraintSeqId"/>
+      <relation type="one" fk-name="CNT_SCHRSI_RES" rel-entity-name="ContentSearchResult">
+        <key-map field-name="contentSearchResultId"/>
+      </relation>
+    </entity>
+    <entity entity-name="ContentSearchResult"
+            package-name="org.ofbiz.content.content"
+            never-cache="true"
+            title="Content Search Result Entity">
+      <field name="contentSearchResultId" type="id-ne"></field>
+      <field name="visitId" type="id"></field>
+      <field name="orderByName" type="long-varchar"></field>
+      <field name="isAscending" type="indicator"></field>
+      <field name="numResults" type="numeric"></field>
+      <field name="secondsTotal" type="floating-point"></field>
+      <field name="searchDate" type="date-time"></field>
+      <prim-key field="contentSearchResultId"/>
+      <relation type="one" fk-name="CNT_SCHRES_VST" rel-entity-name="Visit">
+        <key-map field-name="visitId"/>
+      </relation>
+    </entity>
 </entitymodel>

Modified: ofbiz/trunk/applications/content/script/org/ofbiz/content/content/ContentServices.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/script/org/ofbiz/content/content/ContentServices.xml?rev=1102554&r1=1102553&r2=1102554&view=diff
==============================================================================
--- ofbiz/trunk/applications/content/script/org/ofbiz/content/content/ContentServices.xml (original)
+++ ofbiz/trunk/applications/content/script/org/ofbiz/content/content/ContentServices.xml Fri May 13 03:20:58 2011
@@ -1229,4 +1229,52 @@
         <field-to-result field="subContentList" result-name="subContentList"/>
         <field-to-result field="contentViewList" result-name="subSubContentList"/>
     </simple-method>
+
+    <!-- Content Keyword Services -->
+    <simple-method method-name="createContentKeyword" short-description="create a ContentKeyword">
+        <make-value entity-name="ContentKeyword" value-field="newEntity"/>
+        <set-pk-fields map="parameters" value-field="newEntity"/>
+        <set-nonpk-fields map="parameters" value-field="newEntity"/>
+        <create-value value-field="newEntity"/>
+    </simple-method>
+    
+    <simple-method method-name="updateContentKeyword" short-description="update a ContentKeyword">
+        <entity-one entity-name="ContentKeyword" value-field="lookedUpValue"/>
+        <set-nonpk-fields map="parameters" value-field="lookedUpValue"/>
+        <store-value value-field="lookedUpValue"/>
+    </simple-method>
+    
+    <simple-method method-name="deleteContentKeyword" short-description="delete a ContentKeyword">
+        <entity-one entity-name="ContentKeyword" value-field="lookedUpValue"/>
+        <remove-value value-field="lookedUpValue"/>
+    </simple-method>
+    
+    <simple-method method-name="forceIndexContentKeywords" short-description="induce all the keywords of a content">
+        <entity-one entity-name="Content" value-field="content"/>
+        <call-class-method class-name="org.ofbiz.content.content.ContentKeywordIndex" method-name="forceIndexKeywords">
+            <field field="content" type="org.ofbiz.entity.GenericValue"/>
+        </call-class-method>
+    </simple-method>
+    
+    <simple-method method-name="deleteContentKeywords" short-description="delete all the keywords of a content">
+        <entity-one entity-name="Content" value-field="content"/>
+        <remove-related value-field="content" relation-name="ContentKeyword"/>
+    </simple-method>
+
+    <simple-method method-name="indexContentKeywords" short-description="Index the Keywords for a Content" login-required="false">
+        <!-- this service is meant to be called from an entity ECA for entities that include a contentId -->
+        <!-- if it is the Content entity itself triggering this action, then a [contentInstance] parameter
+            will be passed and we can save a few cycles looking that up -->
+        <set from-field="parameters.contentInstance" field="contentInstance"/>
+        <if-empty field="contentInstance">
+            <set from-field="parameters.contentId" field="findContentMap.contentId"/>
+            <find-by-primary-key entity-name="Content" map="findContentMap" value-field="contentInstance"/>
+        </if-empty>
+
+        <!-- induce keywords-->
+        <call-class-method class-name="org.ofbiz.content.content.ContentKeywordIndex" method-name="indexKeywords">
+            <field field="contentInstance" type="org.ofbiz.entity.GenericValue"/>
+        </call-class-method>
+    </simple-method>
+
 </simple-methods>

Modified: ofbiz/trunk/applications/content/servicedef/services.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/servicedef/services.xml?rev=1102554&r1=1102553&r2=1102554&view=diff
==============================================================================
--- ofbiz/trunk/applications/content/servicedef/services.xml (original)
+++ ofbiz/trunk/applications/content/servicedef/services.xml Fri May 13 03:20:58 2011
@@ -1152,4 +1152,49 @@
         <implements service="permissionInterface"/>
         <attribute name="dataResourceId" type="String" mode="IN" optional="true"/>
     </service>
+
+    <!-- Content Keyword Services -->
+    <service name="createContentKeyword" default-entity-name="ContentKeyword" engine="simple"
+            location="component://content/script/org/ofbiz/content/content/ContentServices.xml" invoke="createContentKeyword" auth="true">
+        <description>Create a ContentKeyword</description>
+        <permission-service service-name="contentGenericPermission" main-action="CREATE"/>
+        <auto-attributes include="pk" mode="IN" optional="false"/>
+        <auto-attributes include="nonpk" mode="IN" optional="true"/>
+    </service>
+
+    <service name="updateContentKeyword" default-entity-name="ContentKeyword" engine="simple"
+            location="component://content/script/org/ofbiz/content/content/ContentServices.xml" invoke="updateContentKeyword" auth="true">
+        <description>Update a ContentKeyword</description>
+        <permission-service service-name="contentGenericPermission" main-action="UPDATE"/>
+        <auto-attributes include="pk" mode="IN" optional="false"/>
+        <auto-attributes include="nonpk" mode="IN" optional="true"/>
+    </service>
+
+    <service name="deleteContentKeyword" default-entity-name="ContentKeyword" engine="simple"
+            location="component://content/script/org/ofbiz/content/content/ContentServices.xml" invoke="deleteContentKeyword" auth="true">
+        <description>Delete a ContentKeyword</description>
+        <permission-service service-name="contentGenericPermission" main-action="DELETE"/>
+        <auto-attributes include="pk" mode="IN" optional="false"/>
+    </service>
+
+    <service name="deleteContentKeywords" engine="simple"
+            location="component://content/script/org/ofbiz/content/content/ContentServices.xml" invoke="deleteContentKeywords" auth="true">
+        <description>Delete all the keywords of a content</description>
+        <permission-service service-name="contentGenericPermission" main-action="DELETE"/>
+        <attribute name="contentId" type="String" mode="IN" optional="false"/>
+    </service>
+
+    <service name="indexContentKeywords" engine="simple"
+                location="component://content/script/org/ofbiz/content/content/ContentServices.xml" invoke="indexContentKeywords" auth="false">
+        <description>Index the Keywords for a Content</description>
+        <attribute name="contentId" type="String" mode="IN" optional="false"/>
+        <attribute name="contentInstance" type="org.ofbiz.entity.GenericValue" mode="IN" optional="true"/>
+    </service>
+
+    <service name="forceIndexContentKeywords" engine="simple"
+            location="component://content/script/org/ofbiz/content/content/ContentServices.xml" invoke="forceIndexContentKeywords" auth="true">
+        <description>Induce all the keywords of a content, ignoring the flag in the Content.</description>
+        <permission-service service-name="contentGenericPermission" main-action="CREATE"/>
+        <attribute name="contentId" type="String" mode="IN" optional="false"/>
+    </service>
 </services>

Added: ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentKeywordIndex.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentKeywordIndex.java?rev=1102554&view=auto
==============================================================================
--- ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentKeywordIndex.java (added)
+++ ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentKeywordIndex.java Fri May 13 03:20:58 2011
@@ -0,0 +1,243 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *******************************************************************************/
+package org.ofbiz.content.content;
+
+import java.io.IOException;
+import java.sql.Timestamp;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import javolution.util.FastList;
+
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.GeneralException;
+import org.ofbiz.base.util.UtilDateTime;
+import org.ofbiz.base.util.UtilMisc;
+import org.ofbiz.base.util.UtilProperties;
+import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.common.KeywordSearchUtil;
+import org.ofbiz.content.data.DataResourceWorker;
+import org.ofbiz.entity.Delegator;
+import org.ofbiz.entity.GenericEntityException;
+import org.ofbiz.entity.GenericValue;
+import org.ofbiz.entity.util.EntityUtil;
+
+/**
+ *  Does indexing in preparation for a keyword search.
+ */
+public class ContentKeywordIndex {
+
+    public static final String module = ContentKeywordIndex.class.getName();
+
+    public static void forceIndexKeywords(GenericValue content) throws GenericEntityException {
+        ContentKeywordIndex.indexKeywords(content, true);
+    }
+
+    public static void indexKeywords(GenericValue content) throws GenericEntityException {
+        ContentKeywordIndex.indexKeywords(content, false);
+    }
+
+    public static void indexKeywords(GenericValue content, boolean doAll) throws GenericEntityException {
+        if (content == null) return;
+        Timestamp nowTimestamp = UtilDateTime.nowTimestamp();
+
+        Delegator delegator = content.getDelegator();
+        if (delegator == null) return;
+        String contentId = content.getString("contentId");
+
+        // get these in advance just once since they will be used many times for the multiple strings to index
+        String separators = KeywordSearchUtil.getSeparators();
+        String stopWordBagOr = KeywordSearchUtil.getStopWordBagOr();
+        String stopWordBagAnd = KeywordSearchUtil.getStopWordBagAnd();
+        boolean removeStems = KeywordSearchUtil.getRemoveStems();
+        Set<String> stemSet = KeywordSearchUtil.getStemSet();
+
+        Map<String, Long> keywords = new TreeMap<String, Long>();
+        List<String> strings = FastList.newInstance();
+
+        int pidWeight = 1;
+        keywords.put(content.getString("contentId").toLowerCase(), Long.valueOf(pidWeight));
+
+        addWeightedKeywordSourceString(content, "dataResourceId", strings);
+        addWeightedKeywordSourceString(content, "contentName", strings);
+        addWeightedKeywordSourceString(content, "description", strings);
+
+        // ContentAttribute
+        List<GenericValue> contentAttributes = delegator.findByAnd("ContentAttribute", UtilMisc.toMap("contentId", contentId));
+        for (GenericValue contentAttribute: contentAttributes) {
+            addWeightedKeywordSourceString(contentAttribute, "attrName", strings);
+            addWeightedKeywordSourceString(contentAttribute, "attrValue", strings);
+        }
+
+        // ContentMetaData
+        List<GenericValue> contentMetaDatas = delegator.findByAnd("ContentMetaData", UtilMisc.toMap("contentId", contentId));
+        for (GenericValue contentMetaData: contentMetaDatas) {
+            addWeightedKeywordSourceString(contentMetaData, "metaDataValue", strings);
+        }
+
+        // ContentRole
+        List<GenericValue> contentRoles = delegator.findByAnd("ContentRole", UtilMisc.toMap("contentId", contentId));
+        for (GenericValue contentRole: contentRoles) {
+            GenericValue party = delegator.findByPrimaryKey("PartyNameView", UtilMisc.toMap("partyId", contentRole.getString("partyId")));
+            if (party != null) {
+                addWeightedKeywordSourceString(party, "description", strings);
+                addWeightedKeywordSourceString(party, "firstName", strings);
+                addWeightedKeywordSourceString(party, "middleName", strings);
+                addWeightedKeywordSourceString(party, "lastName", strings);
+                addWeightedKeywordSourceString(party, "groupName", strings);
+            }
+        }
+
+        // DataResourceRole
+        List<GenericValue> dataResourceRoles = delegator.findByAnd("DataResourceRole", UtilMisc.toMap("dataResourceId", content.getString("dataResourceId")));
+        for (GenericValue dataResourceRole: dataResourceRoles) {
+            GenericValue party = delegator.findByPrimaryKey("PartyNameView", UtilMisc.toMap("partyId", dataResourceRole.getString("partyId")));
+            if (party != null) {
+                addWeightedKeywordSourceString(party, "description", strings);
+                addWeightedKeywordSourceString(party, "firstName", strings);
+                addWeightedKeywordSourceString(party, "middleName", strings);
+                addWeightedKeywordSourceString(party, "lastName", strings);
+                addWeightedKeywordSourceString(party, "groupName", strings);
+            }
+        }
+
+        // Product
+        List<GenericValue> productContentList = delegator.findByAnd("ProductContent", UtilMisc.toMap("contentId", contentId));
+        for (GenericValue productContent: productContentList) {
+            GenericValue product = delegator.findByPrimaryKey("Product", UtilMisc.toMap("productId", productContent.getString("productId")));
+            if (product != null) {
+                addWeightedKeywordSourceString(product, "productName", strings);
+                addWeightedKeywordSourceString(product, "internalName", strings);
+                addWeightedKeywordSourceString(product, "brandName", strings);
+                addWeightedKeywordSourceString(product, "description", strings);
+                addWeightedKeywordSourceString(product, "longDescription", strings);
+            }
+        }
+
+        // ProductCategory
+        List<GenericValue> productCategoryContentList = delegator.findByAnd("ProductCategoryContent", UtilMisc.toMap("contentId", contentId));
+        for (GenericValue productCategoryContent: productCategoryContentList) {
+            GenericValue productCategory = delegator.findByPrimaryKey("ProductCategory", UtilMisc.toMap("productCategoryId", productCategoryContent.getString("productCategoryId")));
+            if (productCategory != null) {
+                addWeightedKeywordSourceString(productCategory, "categoryName", strings);
+                addWeightedKeywordSourceString(productCategory, "description", strings);
+                addWeightedKeywordSourceString(productCategory, "longDescription", strings);
+            }
+        }
+
+        // PartyContent
+        List<GenericValue> partyContents = delegator.findByAnd("PartyContent", UtilMisc.toMap("contentId", contentId));
+        for (GenericValue partyContent: partyContents) {
+            GenericValue party = delegator.findByPrimaryKey("PartyNameView", UtilMisc.toMap("partyId", partyContent.getString("partyId")));
+            if (party != null) {
+                addWeightedKeywordSourceString(party, "description", strings);
+                addWeightedKeywordSourceString(party, "firstName", strings);
+                addWeightedKeywordSourceString(party, "middleName", strings);
+                addWeightedKeywordSourceString(party, "lastName", strings);
+                addWeightedKeywordSourceString(party, "groupName", strings);
+            }
+        }
+
+        // WebSiteContent
+        List<GenericValue> webSiteContents = delegator.findByAnd("WebSiteContent", UtilMisc.toMap("contentId", contentId));
+        for (GenericValue webSiteContent: webSiteContents) {
+            GenericValue webSite = delegator.findByPrimaryKey("WebSite", UtilMisc.toMap("webSiteId", webSiteContent.getString("webSiteId")));
+            if (webSite != null) {
+                addWeightedKeywordSourceString(webSite, "siteName", strings);
+                addWeightedKeywordSourceString(webSite, "httpHost", strings);
+                addWeightedKeywordSourceString(webSite, "httpsHost", strings);
+            }
+        }
+
+        // WorkEffortContent
+        List<GenericValue> workEffortContents = delegator.findByAnd("WorkEffortContent", UtilMisc.toMap("contentId", contentId));
+        for (GenericValue workEffortContent: workEffortContents) {
+            GenericValue workEffort = delegator.findByPrimaryKey("WorkEffort", UtilMisc.toMap("workEffortId", workEffortContent.getString("workEffortId")));
+            if (workEffort != null) {
+                addWeightedKeywordSourceString(workEffort, "workEffortName", strings);
+            }
+        }
+
+        // DataResource
+        GenericValue dataResource = delegator.findByPrimaryKey("DataResource", UtilMisc.toMap("dataResourceId", content.getString("dataResourceId")));
+        if (dataResource != null) {
+            addWeightedKeywordSourceString(dataResource, "dataResourceName", strings);
+            addWeightedKeywordSourceString(dataResource, "objectInfo", strings);
+        }
+        /*List<GenericValue> contentDataResourceViews = delegator.findByAnd("ContentDataResourceView", UtilMisc.toMap("contentId", contentId), null);
+        for (GenericValue contentDataResourceView: contentDataResourceViews) {
+            int weight = 1;
+            addWeightedDataResourceString(contentDataResourceView, weight, strings, delegator, content);
+
+            List<GenericValue> alternateViews = contentDataResourceView.getRelated("ContentAssocDataResourceViewTo", UtilMisc.toMap("caContentAssocTypeId", "ALTERNATE_LOCALE"), UtilMisc.toList("-caFromDate"));
+            alternateViews = EntityUtil.filterByDate(alternateViews, UtilDateTime.nowTimestamp(), "caFromDate", "caThruDate", true);
+            for (GenericValue thisView: alternateViews) {
+                addWeightedDataResourceString(thisView, weight, strings, delegator, content);
+            }
+        }*/
+
+        if (UtilValidate.isNotEmpty(strings)) {
+            for (String str: strings) {
+                // call process keywords method here
+                KeywordSearchUtil.processKeywordsForIndex(str, keywords, separators, stopWordBagAnd, stopWordBagOr, removeStems, stemSet);
+            }
+        }
+
+        List<GenericValue> toBeStored = FastList.newInstance();
+        for (Map.Entry<String, Long> entry: keywords.entrySet()) {
+            GenericValue contentKeyword = delegator.makeValue("ContentKeyword", UtilMisc.toMap("contentId", content.getString("contentId"), "keyword", entry.getKey(), "relevancyWeight", entry.getValue()));
+            toBeStored.add(contentKeyword);
+        }
+        if (toBeStored.size() > 0) {
+            if (Debug.verboseOn()) Debug.logVerbose("[ContentKeywordIndex.indexKeywords] Storing " + toBeStored.size() + " keywords for contentId " + content.getString("contentId"), module);
+
+            if ("true".equals(UtilProperties.getPropertyValue("contentsearch", "index.delete.on_index", "false"))) {
+                // delete all keywords if the properties file says to
+                delegator.removeByAnd("ContentKeyword", UtilMisc.toMap("contentId", content.getString("contentId")));
+            }
+
+            delegator.storeAll(toBeStored);
+        }
+    }
+
+    public static void addWeightedDataResourceString(GenericValue drView, int weight, List<String> strings, Delegator delegator, GenericValue content) {
+        Map<String, Object> drContext = UtilMisc.<String, Object>toMap("content", content);
+        try {
+            String contentText = DataResourceWorker.renderDataResourceAsText(delegator, drView.getString("dataResourceId"), drContext, null, null, false);
+            for (int i = 0; i < weight; i++) {
+                strings.add(contentText);
+            }
+        } catch (IOException e1) {
+            Debug.logError(e1, "Error getting content text to index", module);
+        } catch (GeneralException e1) {
+            Debug.logError(e1, "Error getting content text to index", module);
+        }
+    }
+
+    public static void addWeightedKeywordSourceString(GenericValue value, String fieldName, List<String> strings) {
+        if (value.getString(fieldName) != null) {
+            int weight = 1;
+            for (int i = 0; i < weight; i++) {
+                strings.add(value.getString(fieldName));
+            }
+        }
+    }
+}

Propchange: ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentKeywordIndex.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentKeywordIndex.java
------------------------------------------------------------------------------
    svn:keywords = "Date Rev Author URL Id"

Propchange: ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentKeywordIndex.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearch.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearch.java?rev=1102554&view=auto
==============================================================================
--- ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearch.java (added)
+++ ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearch.java Fri May 13 03:20:58 2011
@@ -0,0 +1,928 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *******************************************************************************/
+package org.ofbiz.content.content;
+
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javolution.util.FastList;
+import javolution.util.FastSet;
+
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.UtilDateTime;
+import org.ofbiz.base.util.UtilMisc;
+import org.ofbiz.base.util.UtilProperties;
+import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.common.KeywordSearchUtil;
+import org.ofbiz.entity.Delegator;
+import org.ofbiz.entity.GenericEntityException;
+import org.ofbiz.entity.GenericValue;
+import org.ofbiz.entity.condition.EntityComparisonOperator;
+import org.ofbiz.entity.condition.EntityCondition;
+import org.ofbiz.entity.condition.EntityConditionList;
+import org.ofbiz.entity.condition.EntityExpr;
+import org.ofbiz.entity.condition.EntityOperator;
+import org.ofbiz.entity.model.DynamicViewEntity;
+import org.ofbiz.entity.model.ModelKeyMap;
+import org.ofbiz.entity.model.ModelViewEntity.ComplexAlias;
+import org.ofbiz.entity.model.ModelViewEntity.ComplexAliasField;
+import org.ofbiz.entity.transaction.GenericTransactionException;
+import org.ofbiz.entity.transaction.TransactionUtil;
+import org.ofbiz.entity.util.EntityFindOptions;
+import org.ofbiz.entity.util.EntityListIterator;
+import org.ofbiz.entity.util.EntityUtil;
+
+public class ContentSearch {
+
+    public static final String module = ContentSearch.class.getName();
+    public static final String resource = "ContentUiLabels";
+
+    public static ArrayList<String> searchContents(List<? extends ContentSearchConstraint> contentSearchConstraintList, ResultSortOrder resultSortOrder, Delegator delegator, String visitId) {
+        ContentSearchContext contentSearchContext = new ContentSearchContext(delegator, visitId);
+
+        contentSearchContext.addContentSearchConstraints(contentSearchConstraintList);
+        contentSearchContext.setResultSortOrder(resultSortOrder);
+
+        ArrayList<String> contentIds = contentSearchContext.doSearch();
+        return contentIds;
+    }
+
+    public static void getAllSubContentIds(String contentId, Set<String> contentIdSet, Delegator delegator, Timestamp nowTimestamp) {
+        if (nowTimestamp == null) {
+            nowTimestamp = UtilDateTime.nowTimestamp();
+        }
+
+        // first make sure the current id is in the Set
+        contentIdSet.add(contentId);
+
+        // now find all sub-categories, filtered by effective dates, and call this routine for them
+        try {
+            List<GenericValue> contentAssocList = delegator.findByAndCache("ContentAssoc", UtilMisc.toMap("contentIdFrom", contentId));
+            for (GenericValue contentAssoc: contentAssocList) {
+                String subContentId = contentAssoc.getString("contentIdTo");
+                if (contentIdSet.contains(subContentId)) {
+                    // if this category has already been traversed, no use doing it again; this will also avoid infinite loops
+                    continue;
+                }
+
+                // do the date filtering in the loop to avoid looping through the list twice
+                if (EntityUtil.isValueActive(contentAssoc, nowTimestamp)) {
+                    getAllSubContentIds(subContentId, contentIdSet, delegator, nowTimestamp);
+                }
+            }
+
+            // Find Content where current contentId = contentParentId; only select minimal fields to keep the size low
+            List<GenericValue> childContentList = delegator.findList("Content", EntityCondition.makeCondition("contentParentId", EntityComparisonOperator.EQUALS, contentId),
+                    UtilMisc.toSet("contentId", "contentParentId"), null, null, true);
+            for (GenericValue childContent: childContentList) {
+                String subContentId = childContent.getString("contentId");
+                if (contentIdSet.contains(subContentId)) {
+                    // if this category has already been traversed, no use doing it again; this will also avoid infinite loops
+                    continue;
+                }
+
+                // do the date filtering in the loop to avoid looping through the list twice
+                getAllSubContentIds(subContentId, contentIdSet, delegator, nowTimestamp);
+            }
+        } catch (GenericEntityException e) {
+            Debug.logError(e, "Error finding sub-categories for content search", module);
+        }
+    }
+
+    public static class ContentSearchContext {
+        public int index = 1;
+        public List<EntityCondition> entityConditionList = FastList.newInstance();
+        public List<String> orderByList = FastList.newInstance();
+        public List<String> fieldsToSelect = UtilMisc.toList("contentId");
+        public DynamicViewEntity dynamicViewEntity = new DynamicViewEntity();
+        public boolean contentIdGroupBy = false;
+        public boolean includedKeywordSearch = false;
+        public Timestamp nowTimestamp = UtilDateTime.nowTimestamp();
+        public List<Set<String>> keywordFixedOrSetAndList = FastList.newInstance();
+        public Set<String> orKeywordFixedSet = FastSet.newInstance();
+        public Set<String> andKeywordFixedSet = FastSet.newInstance();
+        public List<GenericValue> contentSearchConstraintList = FastList.newInstance();
+        public ResultSortOrder resultSortOrder = null;
+        public Integer resultOffset = null;
+        public Integer maxResults = null;
+        protected Delegator delegator = null;
+        protected String visitId = null;
+        protected Integer totalResults = null;
+
+        public ContentSearchContext(Delegator delegator, String visitId) {
+            this.delegator = delegator;
+            this.visitId = visitId;
+            dynamicViewEntity.addMemberEntity("CNT", "Content");
+        }
+
+        public Delegator getDelegator() {
+            return this.delegator;
+        }
+
+        public void addContentSearchConstraints(List<? extends ContentSearchConstraint> contentSearchConstraintList) {
+            // Go through the constraints and add them in
+            for (ContentSearchConstraint constraint: contentSearchConstraintList) {
+                constraint.addConstraint(this);
+            }
+        }
+
+        public void setResultSortOrder(ResultSortOrder resultSortOrder) {
+            this.resultSortOrder = resultSortOrder;
+        }
+
+        public void setResultOffset(Integer resultOffset) {
+            this.resultOffset = resultOffset;
+        }
+
+        public void setMaxResults(Integer maxResults) {
+            this.maxResults = maxResults;
+        }
+
+        public Integer getTotalResults() {
+            return this.totalResults;
+        }
+
+        public ArrayList<String> doSearch() {
+            long startMillis = System.currentTimeMillis();
+
+            // do the query
+            EntityListIterator eli = this.doQuery(delegator);
+            ArrayList<String> contentIds = this.makeContentIdList(eli);
+            if (eli != null) {
+                try {
+                    eli.close();
+                } catch (GenericEntityException e) {
+                    Debug.logError(e, "Error closing ContentSearch EntityListIterator");
+                }
+            }
+
+            long endMillis = System.currentTimeMillis();
+            double totalSeconds = ((double)endMillis - (double)startMillis)/1000.0;
+
+            // store info about results in the database, attached to the user's visitId, if specified
+            this.saveSearchResultInfo(Long.valueOf(contentIds.size()), Double.valueOf(totalSeconds));
+
+            return contentIds;
+        }
+
+        public void finishKeywordConstraints() {
+            if (orKeywordFixedSet.size() == 0 && andKeywordFixedSet.size() == 0 && keywordFixedOrSetAndList.size() == 0) {
+                return;
+            }
+
+            // we know we have a keyword search to do, so keep track of that now...
+            this.includedKeywordSearch = true;
+
+            // if there is anything in the orKeywordFixedSet add it to the keywordFixedOrSetAndList
+            if (orKeywordFixedSet.size() > 0) {
+                // put in keywordFixedOrSetAndList to process with other or lists where at least one is required
+                keywordFixedOrSetAndList.add(orKeywordFixedSet);
+            }
+
+            // remove all or sets from the or set and list where the or set is size 1 and put them in the and list
+            Iterator<Set<String>> keywordFixedOrSetAndTestIter = keywordFixedOrSetAndList.iterator();
+            while (keywordFixedOrSetAndTestIter.hasNext()) {
+                Set<String> keywordFixedOrSet = keywordFixedOrSetAndTestIter.next();
+                if (keywordFixedOrSet.size() == 0) {
+                    keywordFixedOrSetAndTestIter.remove();
+                } else if (keywordFixedOrSet.size() == 1) {
+                    // treat it as just another and
+                    andKeywordFixedSet.add(keywordFixedOrSet.iterator().next());
+                    keywordFixedOrSetAndTestIter.remove();
+                }
+            }
+
+            boolean doingBothAndOr = (keywordFixedOrSetAndList.size() > 1) || (keywordFixedOrSetAndList.size() > 0 && andKeywordFixedSet.size() > 0);
+
+            Debug.logInfo("Finished initial setup of keywords, doingBothAndOr=" + doingBothAndOr + ", andKeywordFixedSet=" + andKeywordFixedSet + "\n keywordFixedOrSetAndList=" + keywordFixedOrSetAndList, module);
+
+            ComplexAlias relevancyComplexAlias = new ComplexAlias("+");
+            if (andKeywordFixedSet.size() > 0) {
+                // add up the relevancyWeight fields from all keyword member entities for a total to sort by
+
+                for (String keyword: andKeywordFixedSet) {
+                    // make index based values and increment
+                    String entityAlias = "PK" + index;
+                    String prefix = "pk" + index;
+                    index++;
+
+                    dynamicViewEntity.addMemberEntity(entityAlias, "ContentKeyword");
+                    dynamicViewEntity.addAlias(entityAlias, prefix + "Keyword", "keyword", null, null, null, null);
+                    dynamicViewEntity.addViewLink("CNT", entityAlias, Boolean.FALSE, ModelKeyMap.makeKeyMapList("contentId"));
+                    entityConditionList.add(EntityCondition.makeCondition(prefix + "Keyword", EntityOperator.LIKE, keyword));
+
+                    //don't add an alias for this, will be part of a complex alias: dynamicViewEntity.addAlias(entityAlias, prefix + "RelevancyWeight", "relevancyWeight", null, null, null, null);
+                    relevancyComplexAlias.addComplexAliasMember(new ComplexAliasField(entityAlias, "relevancyWeight", null, null));
+                }
+
+                //TODO: find out why Oracle and other dbs don't like the query resulting from this and fix: contentIdGroupBy = true;
+
+                if (!doingBothAndOr) {
+                    dynamicViewEntity.addAlias(null, "totalRelevancy", null, null, null, null, null, relevancyComplexAlias);
+                }
+            }
+            if (keywordFixedOrSetAndList.size() > 0) {
+                for (Set<String> keywordFixedOrSet: keywordFixedOrSetAndList) {
+                    // make index based values and increment
+                    String entityAlias = "PK" + index;
+                    String prefix = "pk" + index;
+                    index++;
+
+                    dynamicViewEntity.addMemberEntity(entityAlias, "ContentKeyword");
+                    dynamicViewEntity.addAlias(entityAlias, prefix + "Keyword", "keyword", null, null, null, null);
+                    dynamicViewEntity.addViewLink("CNT", entityAlias, Boolean.FALSE, ModelKeyMap.makeKeyMapList("contentId"));
+                    List<EntityExpr> keywordOrList = FastList.newInstance();
+                    for (String keyword: keywordFixedOrSet) {
+                        keywordOrList.add(EntityCondition.makeCondition(prefix + "Keyword", EntityOperator.LIKE, keyword));
+                    }
+                    entityConditionList.add(EntityCondition.makeCondition(keywordOrList, EntityOperator.OR));
+
+                    contentIdGroupBy = true;
+
+                    if (doingBothAndOr) {
+                        relevancyComplexAlias.addComplexAliasMember(new ComplexAliasField(entityAlias, "relevancyWeight", null, "sum"));
+                    } else {
+                        dynamicViewEntity.addAlias(entityAlias, "totalRelevancy", "relevancyWeight", null, null, null, "sum");
+                    }
+                }
+            }
+
+            if (doingBothAndOr) {
+                dynamicViewEntity.addAlias(null, "totalRelevancy", null, null, null, null, null, relevancyComplexAlias);
+            }
+        }
+
+        public EntityListIterator doQuery(Delegator delegator) {
+            // handle the now assembled or and and keyword fixed lists
+            this.finishKeywordConstraints();
+
+            if (resultSortOrder != null) {
+                resultSortOrder.setSortOrder(this);
+            }
+            dynamicViewEntity.addAlias("CNT", "contentId", null, null, null, Boolean.valueOf(contentIdGroupBy), null);
+            EntityCondition whereCondition = EntityCondition.makeCondition(entityConditionList, EntityOperator.AND);
+
+            // Debug.logInfo("ContentSearch, whereCondition = " + whereCondition.toString(), module);
+
+            EntityFindOptions efo = new EntityFindOptions();
+            efo.setDistinct(true);
+            efo.setResultSetType(EntityFindOptions.TYPE_SCROLL_INSENSITIVE);
+            if (maxResults != null) {
+                efo.setMaxRows(maxResults);
+            }
+
+            EntityListIterator eli = null;
+            try {
+                eli = delegator.findListIteratorByCondition(dynamicViewEntity, whereCondition, null, fieldsToSelect, orderByList, efo);
+            } catch (GenericEntityException e) {
+                Debug.logError(e, "Error in content search", module);
+                return null;
+            }
+
+            return eli;
+        }
+
+        public ArrayList<String> makeContentIdList(EntityListIterator eli) {
+            ArrayList<String> contentIds = new ArrayList<String>(maxResults == null ? 100 : maxResults.intValue());
+            if (eli == null) {
+                Debug.logWarning("The eli is null, returning zero results", module);
+                return contentIds;
+            }
+
+            try {
+                boolean hasResults = false;
+                Object initialResult = null;
+
+                /* this method has been replaced by the following to address issue with SAP DB and possibly other DBs
+                if (resultOffset != null) {
+                    Debug.logInfo("Before relative, current index=" + eli.currentIndex(), module);
+                    hasResults = eli.relative(resultOffset.intValue());
+                } else {
+                    initialResult = eli.next();
+                    if (initialResult != null) {
+                        hasResults = true;
+                    }
+                }
+                 */
+
+                initialResult = eli.next();
+                if (initialResult != null) {
+                    hasResults = true;
+                }
+                if (resultOffset != null && resultOffset.intValue() > 1) {
+                    if (Debug.infoOn()) Debug.logInfo("Before relative, current index=" + eli.currentIndex(), module);
+                    hasResults = eli.relative(resultOffset.intValue() - 1);
+                    initialResult = null;
+                }
+
+                // get the first as the current one
+                GenericValue searchResult = null;
+                if (hasResults) {
+                    if (initialResult != null) {
+                        searchResult = (GenericValue) initialResult;
+                    } else {
+                        searchResult = eli.currentGenericValue();
+                    }
+                }
+
+                if (searchResult == null) {
+                    // nothing to get...
+                    int failTotal = 0;
+                    if (this.resultOffset != null) {
+                        failTotal = this.resultOffset.intValue() - 1;
+                    }
+                    this.totalResults = Integer.valueOf(failTotal);
+                    return contentIds;
+                }
+
+
+                // init numRetreived to one since we have already grabbed the initial one
+                int numRetreived = 1;
+                int duplicatesFound = 0;
+
+                Set<String> contentIdSet = FastSet.newInstance();
+
+                contentIds.add(searchResult.getString("contentId"));
+                contentIdSet.add(searchResult.getString("contentId"));
+
+                while (((searchResult = eli.next()) != null) && (maxResults == null || numRetreived < maxResults.intValue())) {
+                    String contentId = searchResult.getString("contentId");
+                    if (!contentIdSet.contains(contentId)) {
+                        contentIds.add(contentId);
+                        contentIdSet.add(contentId);
+                        numRetreived++;
+                    } else {
+                        duplicatesFound++;
+                    }
+
+                    /*
+                    StringBuilder lineMsg = new StringBuilder("Got search result line: ");
+                    Iterator<String> fieldsToSelectIter = fieldsToSelect.iterator();
+                    while (fieldsToSelectIter.hasNext()) {
+                        String fieldName = fieldsToSelectIter.next();
+                        lineMsg.append(fieldName);
+                        lineMsg.append("=");
+                        lineMsg.append(searchResult.get(fieldName));
+                        if (fieldsToSelectIter.hasNext()) {
+                            lineMsg.append(", ");
+                        }
+                    }
+                    Debug.logInfo(lineMsg.toString(), module);
+                    */
+                }
+
+                if (searchResult != null) {
+                    this.totalResults = eli.getResultsSizeAfterPartialList();
+                }
+                if (this.totalResults == null || this.totalResults.intValue() == 0) {
+                    int total = numRetreived;
+                    if (this.resultOffset != null) {
+                        total += (this.resultOffset.intValue() - 1);
+                    }
+                    this.totalResults = Integer.valueOf(total);
+                }
+
+                Debug.logInfo("Got search values, numRetreived=" + numRetreived + ", totalResults=" + totalResults + ", maxResults=" + maxResults + ", resultOffset=" + resultOffset + ", duplicatesFound(in the current results)=" + duplicatesFound, module);
+
+            } catch (GenericEntityException e) {
+                Debug.logError(e, "Error getting results from the content search query", module);
+            }
+            return contentIds;
+        }
+
+        public void saveSearchResultInfo(Long numResults, Double secondsTotal) {
+            // uses entities: ContentSearchResult and ContentSearchConstraint
+
+            try {
+                // make sure this is in a transaction
+                boolean beganTransaction = TransactionUtil.begin();
+
+                try {
+
+                    GenericValue contentSearchResult = delegator.makeValue("ContentSearchResult");
+                    String contentSearchResultId = delegator.getNextSeqId("ContentSearchResult");
+
+                    contentSearchResult.set("contentSearchResultId", contentSearchResultId);
+                    contentSearchResult.set("visitId", this.visitId);
+                    if (this.resultSortOrder != null) {
+                        contentSearchResult.set("orderByName", this.resultSortOrder.getOrderName());
+                        contentSearchResult.set("isAscending", this.resultSortOrder.isAscending() ? "Y" : "N");
+                    }
+                    contentSearchResult.set("numResults", numResults);
+                    contentSearchResult.set("secondsTotal", secondsTotal);
+                    contentSearchResult.set("searchDate", nowTimestamp);
+                    contentSearchResult.create();
+
+                    int seqId = 1;
+                    for (GenericValue contentSearchConstraint: contentSearchConstraintList) {
+                        contentSearchConstraint.set("contentSearchResultId", contentSearchResultId);
+                        contentSearchConstraint.set("constraintSeqId", Integer.toString(seqId));
+                        contentSearchConstraint.create();
+                        seqId++;
+                    }
+
+                    TransactionUtil.commit(beganTransaction);
+                } catch (GenericEntityException e1) {
+                    String errMsg = "Error saving content search result info/stats";
+                    Debug.logError(e1, errMsg, module);
+                    TransactionUtil.rollback(beganTransaction, errMsg, e1);
+                }
+            } catch (GenericTransactionException e) {
+                Debug.logError(e, "Error saving content search result info/stats", module);
+            }
+        }
+    }
+
+    // ======================================================================
+    // Search Constraint Classes
+    // ======================================================================
+
+    @SuppressWarnings("serial")
+ public static abstract class ContentSearchConstraint implements java.io.Serializable {
+        public ContentSearchConstraint() { }
+
+        public abstract void addConstraint(ContentSearchContext contentSearchContext);
+        /** pretty print for log messages and even UI stuff */
+        public abstract String prettyPrintConstraint(Delegator delegator, boolean detailed, Locale locale);
+    }
+
+
+    @SuppressWarnings("serial")
+ public static class ContentAssocConstraint extends ContentSearchConstraint {
+        public static final String constraintName = "ContentAssoc";
+        protected String contentId;
+        protected String contentAssocTypeId;
+        protected boolean includeSubContents;
+
+        public ContentAssocConstraint(String contentId, String contentAssocTypeId, boolean includeSubContents) {
+            this.contentId = contentId;
+            this.contentAssocTypeId = contentAssocTypeId;
+            this.includeSubContents = includeSubContents;
+        }
+
+        @Override
+        public void addConstraint(ContentSearchContext contentSearchContext) {
+            Set<String> contentIdSet = FastSet.newInstance();
+            if (includeSubContents) {
+                // find all sub-categories recursively, make a Set of contentId
+                ContentSearch.getAllSubContentIds(contentId, contentIdSet, contentSearchContext.getDelegator(), contentSearchContext.nowTimestamp);
+            } else {
+                contentIdSet.add(contentId);
+            }
+
+            // allow assoc from or to the current WE and the contentId on this constraint
+
+            // make index based values and increment
+            String entityAlias;
+            String prefix;
+
+            // do contentId = contentIdFrom, contentIdTo IN contentIdSet
+            entityAlias = "CNT" + contentSearchContext.index;
+            prefix = "cnt" + contentSearchContext.index;
+            contentSearchContext.index++;
+
+            contentSearchContext.dynamicViewEntity.addMemberEntity(entityAlias, "ContentAssoc");
+            contentSearchContext.dynamicViewEntity.addAlias(entityAlias, prefix + "ContentIdFrom", "contentIdFrom", null, null, null, null);
+            contentSearchContext.dynamicViewEntity.addAlias(entityAlias, prefix + "ContentIdTo", "contentIdTo", null, null, null, null);
+            contentSearchContext.dynamicViewEntity.addAlias(entityAlias, prefix + "ContentAssocTypeId", "contentAssocTypeId", null, null, null, null);
+            contentSearchContext.dynamicViewEntity.addAlias(entityAlias, prefix + "FromDate", "fromDate", null, null, null, null);
+            contentSearchContext.dynamicViewEntity.addAlias(entityAlias, prefix + "ThruDate", "thruDate", null, null, null, null);
+            contentSearchContext.dynamicViewEntity.addViewLink("CNT", entityAlias, Boolean.TRUE, ModelKeyMap.makeKeyMapList("contentId","contentIdFrom"));
+
+            List<EntityExpr> assocConditionFromTo = FastList.newInstance();
+            assocConditionFromTo.add(EntityCondition.makeCondition(prefix + "ContentIdTo", EntityOperator.IN, contentIdSet));
+            if (UtilValidate.isNotEmpty(contentAssocTypeId)) {
+                assocConditionFromTo.add(EntityCondition.makeCondition(prefix + "ContentAssocTypeId", EntityOperator.EQUALS, contentAssocTypeId));
+            }
+            assocConditionFromTo.add(EntityCondition.makeCondition(EntityCondition.makeCondition(prefix + "ThruDate", EntityOperator.EQUALS, null), EntityOperator.OR, EntityCondition.makeCondition(prefix + "ThruDate", EntityOperator.GREATER_THAN, contentSearchContext.nowTimestamp)));
+            assocConditionFromTo.add(EntityCondition.makeCondition(prefix + "FromDate", EntityOperator.LESS_THAN, contentSearchContext.nowTimestamp));
+
+            // do contentId = contentIdTo, contentIdFrom IN contentIdSet
+            entityAlias = "CNT" + contentSearchContext.index;
+            prefix = "cnt" + contentSearchContext.index;
+            contentSearchContext.index++;
+
+            contentSearchContext.dynamicViewEntity.addMemberEntity(entityAlias, "ContentAssoc");
+            contentSearchContext.dynamicViewEntity.addAlias(entityAlias, prefix + "ContentIdFrom", "contentIdFrom", null, null, null, null);
+            contentSearchContext.dynamicViewEntity.addAlias(entityAlias, prefix + "ContentIdTo", "contentIdTo", null, null, null, null);
+            contentSearchContext.dynamicViewEntity.addAlias(entityAlias, prefix + "ContentAssocTypeId", "contentAssocTypeId", null, null, null, null);
+            contentSearchContext.dynamicViewEntity.addAlias(entityAlias, prefix + "FromDate", "fromDate", null, null, null, null);
+            contentSearchContext.dynamicViewEntity.addAlias(entityAlias, prefix + "ThruDate", "thruDate", null, null, null, null);
+            contentSearchContext.dynamicViewEntity.addViewLink("CNT", entityAlias, Boolean.TRUE, ModelKeyMap.makeKeyMapList("contentId","contentIdTo"));
+
+            List<EntityExpr> assocConditionToFrom = FastList.newInstance();
+            assocConditionToFrom.add(EntityCondition.makeCondition(prefix + "ContentIdFrom", EntityOperator.IN, contentIdSet));
+            if (UtilValidate.isNotEmpty(contentAssocTypeId)) {
+                assocConditionToFrom.add(EntityCondition.makeCondition(prefix + "ContentAssocTypeId", EntityOperator.EQUALS, contentAssocTypeId));
+            }
+            assocConditionToFrom.add(EntityCondition.makeCondition(EntityCondition.makeCondition(prefix + "ThruDate", EntityOperator.EQUALS, null), EntityOperator.OR, EntityCondition.makeCondition(prefix + "ThruDate", EntityOperator.GREATER_THAN, contentSearchContext.nowTimestamp)));
+            assocConditionToFrom.add(EntityCondition.makeCondition(prefix + "FromDate", EntityOperator.LESS_THAN, contentSearchContext.nowTimestamp));
+
+            // now create and add the combined constraint
+            contentSearchContext.entityConditionList.add(EntityCondition.makeCondition(EntityCondition.makeCondition(assocConditionFromTo, EntityOperator.AND), EntityOperator.OR, EntityCondition.makeCondition(assocConditionToFrom, EntityOperator.AND)));
+
+
+            // add in contentSearchConstraint, don't worry about the contentSearchResultId or constraintSeqId, those will be fill in later
+            contentSearchContext.contentSearchConstraintList.add(contentSearchContext.getDelegator().makeValue("ContentSearchConstraint", UtilMisc.toMap("constraintName", constraintName, "infoString", this.contentId + "," + this.contentAssocTypeId, "includeSubContents", this.includeSubContents ? "Y" : "N")));
+        }
+
+
+        /** pretty print for log messages and even UI stuff */
+        @Override
+        public String prettyPrintConstraint(Delegator delegator, boolean detailed, Locale locale) {
+            GenericValue content = null;
+            GenericValue contentAssocType = null;
+            try {
+                content = delegator.findByPrimaryKeyCache("Content", UtilMisc.toMap("contentId", this.contentId));
+                contentAssocType = delegator.findByPrimaryKeyCache("ContentAssocType", UtilMisc.toMap("contentAssocTypeId", this.contentAssocTypeId));
+            } catch (GenericEntityException e) {
+                Debug.logError(e, "Error looking up ContentAssocConstraint pretty print info: " + e.toString(), module);
+            }
+
+            StringBuilder ppBuf = new StringBuilder();
+            ppBuf.append(UtilProperties.getMessage(resource, "ContentAssoc", locale) + ": ");
+            if (content != null) {
+                ppBuf.append(content.getString("contentName"));
+            }
+            if (content == null || detailed) {
+                ppBuf.append(" [");
+                ppBuf.append(contentId);
+                ppBuf.append("]");
+            }
+            if (UtilValidate.isNotEmpty(this.contentAssocTypeId)) {
+                if (contentAssocType != null) {
+                    ppBuf.append(contentAssocType.getString("description"));
+                }
+                if (contentAssocType == null || detailed) {
+                    ppBuf.append(" [");
+                    ppBuf.append(contentAssocTypeId);
+                    ppBuf.append("]");
+                }
+            }
+            if (this.includeSubContents) {
+                ppBuf.append(" (").append(UtilProperties.getMessage(resource, "ContentIncludeAllSubContents", locale)).append(")");
+            }
+            return ppBuf.toString();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            ContentSearchConstraint psc = (ContentSearchConstraint) obj;
+            if (psc instanceof ContentAssocConstraint) {
+                ContentAssocConstraint that = (ContentAssocConstraint) psc;
+                if (this.includeSubContents != that.includeSubContents) {
+                    return false;
+                }
+                if (this.contentId == null) {
+                    if (that.contentId != null) {
+                        return false;
+                    }
+                } else {
+                    if (!this.contentId.equals(that.contentId)) {
+                        return false;
+                    }
+                }
+                if (this.contentAssocTypeId == null) {
+                    if (that.contentAssocTypeId != null) {
+                        return false;
+                    }
+                } else {
+                    if (!this.contentAssocTypeId.equals(that.contentAssocTypeId)) {
+                        return false;
+                    }
+                }
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    public static class KeywordConstraint extends ContentSearchConstraint {
+        public static final String constraintName = "Keyword";
+        protected String keywordsString;
+        protected boolean anyPrefix;
+        protected boolean anySuffix;
+        protected boolean isAnd;
+        protected boolean removeStems;
+
+        public KeywordConstraint(String keywordsString, boolean anyPrefix, boolean anySuffix, Boolean removeStems, boolean isAnd) {
+            this.keywordsString = keywordsString;
+            this.anyPrefix = anyPrefix;
+            this.anySuffix = anySuffix;
+            this.isAnd = isAnd;
+            if (removeStems != null) {
+                this.removeStems = removeStems.booleanValue();
+            } else {
+                this.removeStems = UtilProperties.propertyValueEquals("keywordsearch", "remove.stems", "true");
+            }
+        }
+
+        public Set<String> makeFullKeywordSet(Delegator delegator) {
+            Set<String> keywordSet = KeywordSearchUtil.makeKeywordSet(this.keywordsString, null, true);
+            Set<String> fullKeywordSet = new TreeSet<String>();
+
+            // expand the keyword list according to the thesaurus and create a new set of keywords
+            for (String keyword: keywordSet) {
+                Set<String> expandedSet = new TreeSet<String>();
+                boolean replaceEntered = KeywordSearchUtil.expandKeywordForSearch(keyword, expandedSet, delegator);
+                fullKeywordSet.addAll(expandedSet);
+                if (!replaceEntered) {
+                    fullKeywordSet.add(keyword);
+                }
+            }
+
+            return fullKeywordSet;
+        }
+
+        @Override
+        public void addConstraint(ContentSearchContext contentSearchContext) {
+            // just make the fixed keyword lists and put them in the context
+            if (isAnd) {
+                // when isAnd is true we need to make a list of keyword sets where each set corresponds to one
+                //incoming/entered keyword and contains all of the expanded keywords plus the entered keyword if none of
+                //the expanded keywords are flagged as replacements; now the tricky part: each set should be or'ed together,
+                //but then the sets should be and'ed to produce the overall expression; create the SQL for this
+                //needs some work as the current method only support a list of and'ed words and a list of or'ed words, not
+                //a list of or'ed sets to be and'ed together
+                Set<String> keywordSet = KeywordSearchUtil.makeKeywordSet(this.keywordsString, null, true);
+
+                // expand the keyword list according to the thesaurus and create a new set of keywords
+                for (String keyword: keywordSet) {
+                    Set<String> expandedSet = new TreeSet<String>();
+                    boolean replaceEntered = KeywordSearchUtil.expandKeywordForSearch(keyword, expandedSet, contentSearchContext.getDelegator());
+                    if (!replaceEntered) {
+                        expandedSet.add(keyword);
+                    }
+                    Set<String> fixedSet = KeywordSearchUtil.fixKeywordsForSearch(expandedSet, anyPrefix, anySuffix, removeStems, isAnd);
+                    Set<String> fixedKeywordSet = FastSet.newInstance();
+                    fixedKeywordSet.addAll(fixedSet);
+                    contentSearchContext.keywordFixedOrSetAndList.add(fixedKeywordSet);
+                }
+            } else {
+                // when isAnd is false, just add all of the new entries to the big list
+                Set<String> keywordFirstPass = makeFullKeywordSet(contentSearchContext.getDelegator()); // includes keyword expansion, etc
+                Set<String> keywordSet = KeywordSearchUtil.fixKeywordsForSearch(keywordFirstPass, anyPrefix, anySuffix, removeStems, isAnd);
+                contentSearchContext.orKeywordFixedSet.addAll(keywordSet);
+            }
+
+            // add in contentSearchConstraint, don't worry about the contentSearchResultId or constraintSeqId, those will be fill in later
+            Map<String, String> valueMap = UtilMisc.toMap("constraintName", constraintName, "infoString", this.keywordsString);
+            valueMap.put("anyPrefix", this.anyPrefix ? "Y" : "N");
+            valueMap.put("anySuffix", this.anySuffix ? "Y" : "N");
+            valueMap.put("isAnd", this.isAnd ? "Y" : "N");
+            valueMap.put("removeStems", this.removeStems ? "Y" : "N");
+            contentSearchContext.contentSearchConstraintList.add(contentSearchContext.getDelegator().makeValue("ContentSearchConstraint", valueMap));
+        }
+
+        /** pretty print for log messages and even UI stuff */
+        @Override
+        public String prettyPrintConstraint(Delegator delegator, boolean detailed, Locale locale) {
+            StringBuilder ppBuf = new StringBuilder();
+            ppBuf.append(UtilProperties.getMessage(resource, "ContentKeywords", locale)).append(": \"");
+            ppBuf.append(this.keywordsString).append("\", ").append(UtilProperties.getMessage(resource, "ContentKeywordWhere", locale)).append(" ");
+            ppBuf.append(isAnd ? UtilProperties.getMessage(resource, "ContentKeywordAllWordsMatch", locale) : UtilProperties.getMessage(resource, "ContentKeywordAnyWordMatches", locale));
+            return ppBuf.toString();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            ContentSearchConstraint psc = (ContentSearchConstraint) obj;
+            if (psc instanceof KeywordConstraint) {
+                KeywordConstraint that = (KeywordConstraint) psc;
+                if (this.anyPrefix != that.anyPrefix) {
+                    return false;
+                }
+                if (this.anySuffix != that.anySuffix) {
+                    return false;
+                }
+                if (this.isAnd != that.isAnd) {
+                    return false;
+                }
+                if (this.removeStems != that.removeStems) {
+                    return false;
+                }
+                if (this.keywordsString == null) {
+                    if (that.keywordsString != null) {
+                        return false;
+                    }
+                } else {
+                    if (!this.keywordsString.equals(that.keywordsString)) {
+                        return false;
+                    }
+                }
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    public static class LastUpdatedRangeConstraint extends ContentSearchConstraint {
+        public static final String constraintName = "LastUpdatedRange";
+        protected Timestamp fromDate;
+        protected Timestamp thruDate;
+
+        public LastUpdatedRangeConstraint(Timestamp fromDate, Timestamp thruDate) {
+            this.fromDate = fromDate;
+            this.thruDate = thruDate;
+        }
+
+        @Override
+        public void addConstraint(ContentSearchContext contentSearchContext) {
+            contentSearchContext.dynamicViewEntity.addAlias("CNT", "lastModifiedDate", "lastModifiedDate", null, null, null, null);
+
+            EntityConditionList<EntityExpr> dateConditions = null;
+            EntityExpr dateCondition=null;
+            if (fromDate !=null && thruDate!=null) {
+            dateConditions= EntityCondition.makeCondition(UtilMisc.toList(
+                    EntityCondition.makeCondition("lastModifiedDate", EntityOperator.GREATER_THAN_EQUAL_TO, fromDate),
+                    EntityCondition.makeCondition("lastModifiedDate", EntityOperator.LESS_THAN_EQUAL_TO, thruDate)), EntityOperator.AND);
+            } if (fromDate !=null) {
+                dateCondition=EntityCondition.makeCondition("lastModifiedDate", EntityOperator.GREATER_THAN_EQUAL_TO, fromDate);
+            } else if (thruDate != null) {
+                dateCondition = EntityCondition.makeCondition("lastModifiedDate", EntityOperator.LESS_THAN_EQUAL_TO, thruDate);
+            }
+            EntityConditionList<? extends EntityCondition> conditions = null;
+            if (fromDate !=null && thruDate!=null) {
+                conditions=EntityCondition.makeCondition(UtilMisc.toList(
+                    dateConditions,
+                    EntityCondition.makeCondition("lastModifiedDate", EntityOperator.EQUALS, null)),
+                    EntityOperator.OR);
+            } else {
+                conditions=EntityCondition.makeCondition(UtilMisc.toList(
+                        dateCondition,
+                        EntityCondition.makeCondition("lastModifiedDate", EntityOperator.EQUALS, null)),
+                        EntityOperator.OR);
+            }
+
+            contentSearchContext.entityConditionList.add(conditions);
+
+            // add in contentSearchConstraint, don't worry about the contentSearchResultId or constraintSeqId, those will be fill in later
+            contentSearchContext.contentSearchConstraintList.add(contentSearchContext.getDelegator().makeValue("ContentSearchConstraint", UtilMisc.toMap("constraintName", constraintName, "infoString","fromDate : " + fromDate + " thruDate : " + thruDate)));
+        }
+
+        /** pretty print for log messages and even UI stuff */
+        @Override
+        public String prettyPrintConstraint(Delegator delegator, boolean detailed, Locale locale) {
+            StringBuilder ppBuf = new StringBuilder();
+            ppBuf.append(UtilProperties.getMessage(resource, "ContentLastModified", locale)).append(": \"");
+            ppBuf.append(fromDate).append("-").append(thruDate).append("\", ").append(UtilProperties.getMessage(resource, "ContentLastModified", locale)).append(" ");
+            return ppBuf.toString();
+        }
+
+
+        @Override
+        public boolean equals(Object obj) {
+            ContentSearchConstraint psc = (ContentSearchConstraint) obj;
+            if (psc instanceof LastUpdatedRangeConstraint) {
+                LastUpdatedRangeConstraint that = (LastUpdatedRangeConstraint) psc;
+                if (this.fromDate == null) {
+                    if (that.fromDate != null) {
+                        return false;
+                    }
+                } else {
+                    if (!this.fromDate.equals(that.fromDate)) {
+                        return false;
+                    }
+                }
+                if (this.thruDate == null) {
+                    if (that.thruDate != null) {
+                        return false;
+                    }
+                } else {
+                    if (!this.thruDate.equals(that.thruDate)) {
+                        return false;
+                    }
+                }
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    // ======================================================================
+    // Result Sort Classes
+    // ======================================================================
+
+    @SuppressWarnings("serial")
+    public static abstract class ResultSortOrder implements java.io.Serializable {
+        public ResultSortOrder() {
+        }
+
+        public abstract void setSortOrder(ContentSearchContext contentSearchContext);
+        public abstract String getOrderName();
+        public abstract String prettyPrintSortOrder(boolean detailed, Locale locale);
+        public abstract boolean isAscending();
+    }
+
+    @SuppressWarnings("serial")
+    public static class SortKeywordRelevancy extends ResultSortOrder {
+        public SortKeywordRelevancy() {
+        }
+
+        @Override
+        public void setSortOrder(ContentSearchContext contentSearchContext) {
+            if (contentSearchContext.includedKeywordSearch) {
+                // we have to check this in order to be sure that there is a totalRelevancy to sort by...
+                contentSearchContext.orderByList.add("-totalRelevancy");
+                contentSearchContext.fieldsToSelect.add("totalRelevancy");
+            }
+        }
+
+        @Override
+        public String getOrderName() {
+            return "KeywordRelevancy";
+        }
+
+        @Override
+        public String prettyPrintSortOrder(boolean detailed, Locale locale) {
+            return UtilProperties.getMessage(resource, "ContentKeywordRelevancy", locale);
+        }
+
+        @Override
+        public boolean isAscending() {
+            return false;
+        }
+    }
+
+    @SuppressWarnings("serial")
+    public static class SortContentField extends ResultSortOrder {
+        protected String fieldName;
+        protected boolean ascending;
+
+        /** Some good field names to try might include:
+         * [contentName]
+         * [totalQuantityOrdered] for most popular or most purchased
+         * [lastModifiedDate]
+         *
+         *  You can also include any other field on the Content entity.
+         */
+        public SortContentField(String fieldName, boolean ascending) {
+            this.fieldName = fieldName;
+            this.ascending = ascending;
+        }
+
+        @Override
+        public void setSortOrder(ContentSearchContext contentSearchContext) {
+            if (contentSearchContext.getDelegator().getModelEntity("Content").isField(fieldName)) {
+                contentSearchContext.dynamicViewEntity.addAlias("CNT", fieldName);
+            }
+            if (ascending) {
+                contentSearchContext.orderByList.add("+" + fieldName);
+            } else {
+                contentSearchContext.orderByList.add("-" + fieldName);
+            }
+            contentSearchContext.fieldsToSelect.add(fieldName);
+        }
+
+        @Override
+        public String getOrderName() {
+            return "ContentField:" + this.fieldName;
+        }
+
+        @Override
+        public String prettyPrintSortOrder(boolean detailed, Locale locale) {
+            if ("contentName".equals(this.fieldName)) {
+                return UtilProperties.getMessage(resource, "ContentName", locale);
+            } else if ("totalQuantityOrdered".equals(this.fieldName)) {
+                return UtilProperties.getMessage(resource, "ContentPopularityByOrders", locale);
+            } else if ("totalTimesViewed".equals(this.fieldName)) {
+                return UtilProperties.getMessage(resource, "ContentPopularityByViews", locale);
+            } else if ("averageCustomerRating".equals(this.fieldName)) {
+                return UtilProperties.getMessage(resource, "ContentCustomerRating", locale);
+            }
+            return this.fieldName;
+        }
+
+        @Override
+        public boolean isAscending() {
+            return this.ascending;
+        }
+    }
+}

Propchange: ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearch.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearch.java
------------------------------------------------------------------------------
    svn:keywords = "Date Rev Author URL Id"

Propchange: ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearch.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearchEvents.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearchEvents.java?rev=1102554&view=auto
==============================================================================
--- ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearchEvents.java (added)
+++ ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearchEvents.java Fri May 13 03:20:58 2011
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *******************************************************************************/
+package org.ofbiz.content.content;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import javolution.util.FastMap;
+
+import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.entity.Delegator;
+import org.ofbiz.webapp.stats.VisitHandler;
+import org.ofbiz.content.content.ContentSearch.ResultSortOrder;
+import org.ofbiz.content.content.ContentSearch.ContentSearchConstraint;
+import org.ofbiz.content.content.ContentSearch.ContentSearchContext;
+import org.ofbiz.content.content.ContentSearchSession.ContentSearchOptions;
+
+
+public class ContentSearchEvents {
+
+    public static final String module = ContentSearchEvents.class.getName();
+
+    public static Map<String, Object> getContentSearchResult(HttpServletRequest request, Delegator delegator) {
+
+        // ========== Create View Indexes
+        int viewIndex = 0;
+        int viewSize = 20;
+        int highIndex = 0;
+        int lowIndex = 0;
+        int listSize = 0;
+
+        HttpSession session = request.getSession();
+        ContentSearchOptions contentSearchOptions = ContentSearchSession.getContentSearchOptions(session);
+
+        Integer viewIndexInteger = contentSearchOptions.getViewIndex();
+        if (viewIndexInteger != null) viewIndex = viewIndexInteger.intValue();
+        Integer viewSizeInteger = contentSearchOptions.getViewSize();
+        if (viewSizeInteger != null) viewSize = viewSizeInteger.intValue();
+
+        lowIndex = viewIndex * viewSize;
+        highIndex = (viewIndex + 1) * viewSize;
+
+        // setup resultOffset and maxResults, noting that resultOffset is 1 based, not zero based as these numbers
+        Integer resultOffset = Integer.valueOf(lowIndex + 1);
+        Integer maxResults = Integer.valueOf(viewSize);
+
+        // ========== Do the actual search
+        ArrayList<String> contentIds = null;
+        String visitId = VisitHandler.getVisitId(session);
+        List<ContentSearchConstraint> contentSearchConstraintList = ContentSearchOptions.getConstraintList(session);
+        // if no constraints, don't do a search...
+        if (UtilValidate.isNotEmpty(contentSearchConstraintList)) {
+            // if the search options have changed since the last search, put at the beginning of the options history list
+            ContentSearchSession.checkSaveSearchOptionsHistory(session);
+
+            ResultSortOrder resultSortOrder = ContentSearchOptions.getResultSortOrder(request);
+
+            ContentSearchContext contentSearchContext = new ContentSearchContext(delegator, visitId);
+            contentSearchContext.addContentSearchConstraints(contentSearchConstraintList);
+
+            contentSearchContext.setResultSortOrder(resultSortOrder);
+            contentSearchContext.setResultOffset(resultOffset);
+            contentSearchContext.setMaxResults(maxResults);
+
+            contentIds = contentSearchContext.doSearch();
+
+            Integer totalResults = contentSearchContext.getTotalResults();
+            if (totalResults != null) {
+                listSize = totalResults.intValue();
+            }
+        }
+
+        if (listSize < highIndex) {
+            highIndex = listSize;
+        }
+
+        // ========== Setup other display info
+        List<String> searchConstraintStrings = ContentSearchSession.searchGetConstraintStrings(false, session, delegator);
+        String searchSortOrderString = ContentSearchSession.searchGetSortOrderString(false, request);
+
+        // ========== populate the result Map
+        Map<String, Object> result = FastMap.newInstance();
+
+        result.put("contentIds", contentIds);
+        result.put("viewIndex", Integer.valueOf(viewIndex));
+        result.put("viewSize", Integer.valueOf(viewSize));
+        result.put("listSize", Integer.valueOf(listSize));
+        result.put("lowIndex", Integer.valueOf(lowIndex));
+        result.put("highIndex", Integer.valueOf(highIndex));
+        result.put("searchConstraintStrings", searchConstraintStrings);
+        result.put("searchSortOrderString", searchSortOrderString);
+
+        return result;
+    }
+
+
+}

Propchange: ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearchEvents.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearchEvents.java
------------------------------------------------------------------------------
    svn:keywords = "Date Rev Author URL Id"

Propchange: ofbiz/trunk/applications/content/src/org/ofbiz/content/content/ContentSearchEvents.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain