Last active
November 1, 2017 22:45
-
-
Save jardineworks/eb9e39290536ef0efd3c to your computer and use it in GitHub Desktop.
SB + Custom Indexer + Search
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--------------------------------------------------------------------------------------------------------- | |
STEP #1: Create new service builder portlet | |
--------------------------------------------------------------------------------------------------------- | |
1. Project name sample-recipe-portlet | |
2. Plugin type: Service Builder Portlet | |
3. Portlet type should be MVCPortlet (at least that is my prefrence) | |
4. | |
--------------------------------------------------------------------------------------------------------- | |
STEP #2: Add service.xml definition for a Recipe Model | |
--------------------------------------------------------------------------------------------------------- | |
1. Open WEB-INF/service.xml | |
2. Copy and paste: | |
<?xml version="1.0" encoding="UTF-8"?> | |
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.2.0//EN" "http://www.liferay.com/dtd/liferay-service-builder_6_2_0.dtd"> | |
<service-builder package-path="com.liferay.sample"> | |
<author>devlife tutorial</author> | |
<namespace>DEVLIFE</namespace> | |
<entity name="Recipe" uuid="true" local-service="true" remote-service="true"> | |
<!-- PK fields --> | |
<column name="recipeId" type="long" primary="true" /> | |
<!-- Group instance --> | |
<column name="groupId" type="long" /> | |
<!-- Audit fields --> | |
<column name="companyId" type="long" /> | |
<column name="userId" type="long" /> | |
<column name="userName" type="String" /> | |
<column name="createDate" type="Date" /> | |
<column name="modifiedDate" type="Date" /> | |
<!-- Other fields --> | |
<column name="title" type="String" /> | |
<column name="summary" type="String" /> | |
<column name="description" type="String" /> | |
<column name="servings" type="int" /> | |
<column name="prepTime" type="int" /> | |
<column name="cookTime" type="int" /> | |
<column name="ingredients" type="String" /> | |
<column name="instructions" type="String" /> | |
<!-- Order --> | |
<order by="asc"> | |
<order-column name="title" /> | |
</order> | |
<!-- Finder methods --> | |
<finder name="Title" return-type="Collection"> | |
<finder-column name="title" /> | |
</finder> | |
</entity> | |
</service-builder> | |
3. Save. | |
4. Build service. | |
5. Deploy. | |
--------------------------------------------------------------------------------------------------------- | |
STEP #4: Create a test page and add your portlet | |
--------------------------------------------------------------------------------------------------------- | |
1. Create a page called "Recipes" | |
2. Set layout to 1 column | |
3. Add the portlet to the page. | |
--------------------------------------------------------------------------------------------------------- | |
STEP #5: Update portlet to add recipes | |
--------------------------------------------------------------------------------------------------------- | |
1. create html folder | |
2. create common folder | |
3. create recipe folder | |
4. Create init.jsp file inside common folder and add the following -- | |
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %> | |
<%@ taglib uri="http://alloy.liferay.com/tld/aui" prefix="aui" %> | |
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %> | |
<%@ taglib uri="http://liferay.com/tld/util" prefix="liferay-util" %> | |
<%@ taglib uri="http://liferay.com/tld/theme" prefix="theme" %> | |
<%@ taglib uri="http://liferay.com/tld/portlet" prefix="liferay-portlet" %> | |
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> | |
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %> | |
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> | |
<%@ page import="javax.portlet.PortletPreferences"%> | |
<%@ page import="com.liferay.portlet.PortletPreferencesFactoryUtil"%> | |
<%@ page import="com.liferay.portal.kernel.util.Validator"%> | |
<%@ page import="com.liferay.portal.kernel.util.ParamUtil"%> | |
<%@ page import="com.liferay.portal.kernel.util.GetterUtil"%> | |
<%@ page import="com.liferay.portal.kernel.util.StringPool"%> | |
<%@ page import="com.liferay.portal.kernel.util.Constants"%> | |
<%@ page import="java.util.List" %> | |
<%@ page import="java.util.ArrayList" %> | |
<%@ page import="java.util.Arrays" %> | |
<%@ page import="java.util.Iterator" %> | |
<%@ page import="com.liferay.portal.kernel.log.LogFactoryUtil" %> | |
<%@ page import="com.liferay.portal.kernel.log.Log" %> | |
<%@page import="com.liferay.portlet.PortletURLFactoryUtil"%> | |
<%@page import="com.liferay.portal.kernel.portlet.LiferayPortletURL"%> | |
<%@page import="com.liferay.portal.kernel.portlet.LiferayPortlet"%> | |
<%@page import="com.liferay.portal.service.LayoutLocalServiceUtil"%> | |
<%@page import="com.liferay.portal.model.Layout"%> | |
<portlet:defineObjects /> | |
<theme:defineObjects/> | |
<% | |
PortletPreferences preferences = renderRequest.getPreferences(); | |
String portletResource = ParamUtil.getString( request, "portletResource" ); | |
if ( Validator.isNotNull( portletResource ) ) | |
{ | |
preferences = PortletPreferencesFactoryUtil.getPortletSetup( request, portletResource ); | |
} | |
String redirect = ParamUtil.getString( request, "redirect" ); | |
%> | |
5. Save and close file. | |
6. Create an init.jsp file inside /html/recipe and add the following code. | |
<%@ include file="/html/common/init.jsp" %> | |
7. Creare a view.jsp file inside /html/recipe and add the following code. | |
<%@ include file="init.jsp" %> | |
<portlet:actionURL name="add" var="addRecipeURL" /> | |
<div> | |
<h3>Recipe Portlet</h3> | |
<hr/> | |
<aui:form name="fm" method="post" action="${ addRecipeURL }"> | |
<aui:fieldset> | |
<aui:input name="title" label="recipe-title" /> | |
<aui:input type="textarea" name="summary" label="recipe-summary" /> | |
<aui:input type="textarea" name="description" label="recipe-description" /> | |
<aui:input name="servings" label="recipe-servings"/> | |
<aui:input name="prepTime" label="recipe-prep-time"/> | |
<aui:input name="cookTime" label="recipe-cook-time" /> | |
<aui:input type="textarea" name="ingredients" label="recipe-ingredients" /> | |
<aui:input type="textarea" name="instructions" label="recipe-instructions" /> | |
</aui:fieldset> | |
<aui:button-row> | |
<aui:button type="submit" value="add-recipe"/> | |
</aui:button-row> | |
</aui:form> | |
</div> | |
8. Save and close the file. | |
9. Modify the portlet.xml file to reflect your new paths (/html/common and /html/recipe) with the following code -- | |
<?xml version="1.0"?> | |
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0"> | |
<portlet> | |
<portlet-name>sample-recipe</portlet-name> | |
<display-name>Sample Recipe Portlet</display-name> | |
<portlet-class>com.devlife.example.liferay.portlet.RecipePortlet</portlet-class> | |
<init-param> | |
<name>view-template</name> | |
<value>/html/recipe/view.jsp</value> | |
</init-param> | |
<expiration-cache>0</expiration-cache> | |
<supports> | |
<mime-type>text/html</mime-type> | |
</supports> | |
<resource-bundle>content/Language</resource-bundle> | |
<portlet-info> | |
<title>Sample Recipe Portlet</title> | |
<short-title>Sample Recipe Portlet</short-title> | |
<keywords>Sample Recipe Portlet</keywords> | |
</portlet-info> | |
<security-role-ref> | |
<role-name>user</role-name> | |
</security-role-ref> | |
</portlet> | |
</portlet-app> | |
10. Save and close the file. | |
11. Add the content folder and the Language.properties file inside it. | |
12. Aadd the following content to the Language.properties file | |
## | |
## Recipe Portlet | |
## | |
# | |
# Recipe form entry labels | |
# | |
recipe-title=Title | |
recipe-summary=Summary | |
recipe-description= Description | |
recipe-servings=Serves | |
recipe-prep-time=Prep Time | |
recipe-cook-time=Cook Time | |
recipe-ingredients=Ingredients | |
recipe-instructions=Instructions | |
add-recipe=Add Recipe | |
12. Save and close the file. | |
13. Create a new class file com.devlife.example.liferay.portlet.RecipePortlet. | |
14. Set the contents of the class to the follwoing -- | |
package com.devlife.example.liferay.portlet; | |
import java.util.Date; | |
import javax.portlet.ActionRequest; | |
import javax.portlet.ActionResponse; | |
import javax.portlet.ProcessAction; | |
import com.liferay.counter.service.CounterLocalServiceUtil; | |
import com.liferay.portal.kernel.log.Log; | |
import com.liferay.portal.kernel.log.LogFactoryUtil; | |
import com.liferay.portal.kernel.util.ParamUtil; | |
import com.liferay.portal.kernel.util.Validator; | |
import com.liferay.portal.model.User; | |
import com.liferay.portal.util.PortalUtil; | |
import com.liferay.sample.model.Recipe; | |
import com.liferay.sample.service.RecipeLocalServiceUtil; | |
import com.liferay.util.bridges.mvc.MVCPortlet; | |
public class RecipePortlet extends MVCPortlet | |
{ | |
// class logger | |
private static final Log _log = LogFactoryUtil.getLog(RecipePortlet.class); | |
public static final String PARAM_TITLE = "title"; | |
public static final String PARAM_SUMMARY = "summary"; | |
public static final String PARAM_DESCRIPTION = "description"; | |
public static final String PARAM_SERVINGS = "servings"; | |
public static final String PARAM_PREP_TIME = "prepTime"; | |
public static final String PARAM_COOK_TIME = "cookTime"; | |
public static final String PARAM_INGREDIENTS = "ingredients"; | |
public static final String PARAM_INSTRUCTIONS = "instructions"; | |
public static final String NO_VALUE = "[none]"; | |
@ProcessAction(name = "add") | |
public void add(ActionRequest actionRequest, ActionResponse actionResponse) | |
{ | |
String title = ParamUtil.getString(actionRequest, PARAM_TITLE, NO_VALUE); | |
String summary = ParamUtil.getString(actionRequest, PARAM_SUMMARY, NO_VALUE); | |
String description = ParamUtil.getString(actionRequest, PARAM_DESCRIPTION, NO_VALUE); | |
int servings = ParamUtil.getInteger(actionRequest, PARAM_SERVINGS, 0); | |
int prepTime = ParamUtil.getInteger(actionRequest, PARAM_PREP_TIME, 0); | |
int cookTime = ParamUtil.getInteger(actionRequest, PARAM_COOK_TIME, 0); | |
String ingredients = ParamUtil.getString(actionRequest, PARAM_INGREDIENTS, NO_VALUE); | |
String instructions = ParamUtil.getString(actionRequest, PARAM_INSTRUCTIONS, NO_VALUE); | |
try | |
{ | |
// grab the objects we need for auditing fields. | |
Date now = new Date(); | |
User user = PortalUtil.getUser(actionRequest); | |
// make a template recipe | |
Recipe r = RecipeLocalServiceUtil.createRecipe(CounterLocalServiceUtil.increment(Recipe.class.getName())); | |
// audit fields | |
r.setGroupId( PortalUtil.getScopeGroupId(actionRequest) ); | |
r.setCompanyId( PortalUtil.getCompanyId(actionRequest) ); | |
if ( Validator.isNotNull(user) ) | |
{ | |
r.setUserId( PortalUtil.getUserId(actionRequest) ); | |
r.setUserName( PortalUtil.getUserName( PortalUtil.getUserId(actionRequest), "test") ); | |
} | |
else | |
{ | |
_log.warn("Failed to locate used in action request. Some audit fields for recipe " + title + " may be missing."); | |
} | |
r.setCreateDate( now ); | |
r.setModifiedDate( now ); | |
// fill in the recipe details | |
r.setTitle(title); | |
r.setSummary(summary); | |
r.setDescription(description); | |
r.setServings(servings); | |
r.setPrepTime(prepTime); | |
r.setCookTime(cookTime); | |
r.setIngredients(ingredients); | |
r.setInstructions(instructions); | |
r = RecipeLocalServiceUtil.addRecipe(r); | |
} | |
catch (Exception e) | |
{ | |
_log.error("Problem occurred while trying to add recipe.",e); | |
} | |
} | |
} | |
15. Save and close the file. | |
16. Add some model hints so we can store some longer text for some of the recipe fields. Open, under src/META-INF the portlet-model-hints.xml file and set the contents to the following -- | |
<?xml version="1.0"?> | |
<model-hints> | |
<hint-collection name="TEXTAREA"> | |
<hint name="max-length">2000</hint> | |
</hint-collection> | |
<model name="com.liferay.sample.model.Recipe"> | |
<field name="recipeId" type="long" /> | |
<field name="groupId" type="long" /> | |
<field name="companyId" type="long" /> | |
<field name="userId" type="long" /> | |
<field name="userName" type="String" /> | |
<field name="createDate" type="Date" /> | |
<field name="modifiedDate" type="Date" /> | |
<field name="title" type="String" /> | |
<field name="summary" type="String"> | |
<hint-collection name="TEXTAREA" /> | |
</field> | |
<field name="description" type="String"> | |
<hint-collection name="TEXTAREA" /> | |
</field> | |
<field name="servings" type="int" /> | |
<field name="prepTime" type="int" /> | |
<field name="cookTime" type="int" /> | |
<field name="ingredients" type="String"> | |
<hint-collection name="TEXTAREA" /> | |
</field> | |
<field name="instructions" type="String"> | |
<hint-collection name="TEXTAREA" /> | |
</field> | |
</model> | |
</model-hints> | |
17. Save and close the file. | |
18. Deploy. | |
19. Reload the page with your portlet to see the form. | |
20. Add a recipe and validate that it is there in the database. | |
--------------------------------------------------------------------------------------------------------- | |
STEP #6: | |
--------------------------------------------------------------------------------------------------------- | |
1. Create a new class com.devlife.example.liferay.portlet.search.RecipeIndexer | |
2. Make the contents of the class -- | |
package com.devlife.example.liferay.portlet.search; | |
import java.util.Locale; | |
import javax.portlet.PortletURL; | |
import com.liferay.portal.kernel.log.Log; | |
import com.liferay.portal.kernel.log.LogFactoryUtil; | |
import com.liferay.portal.kernel.search.BaseIndexer; | |
import com.liferay.portal.kernel.search.Document; | |
import com.liferay.portal.kernel.search.Hits; | |
import com.liferay.portal.kernel.search.SearchContext; | |
import com.liferay.portal.kernel.search.SearchEngineUtil; | |
import com.liferay.portal.kernel.search.SearchException; | |
import com.liferay.portal.kernel.search.Summary; | |
import com.liferay.sample.model.Recipe; | |
public class RecipeIndexer extends BaseIndexer | |
{ | |
// class logger | |
private static final Log _log = LogFactoryUtil.getLog(RecipeIndexer.class); | |
public static final String[] CLASS_NAMES = {Recipe.class.getName()}; | |
public static final String PORTLET_ID = "samplerecipe_WAR_samplerecipeportlet"; | |
@Override | |
public String[] getClassNames() | |
{ | |
return CLASS_NAMES; | |
} | |
@Override | |
public String getPortletId() | |
{ | |
return PORTLET_ID; | |
} | |
@Override | |
public Hits search(SearchContext searchContext) throws SearchException | |
{ | |
_log.info("** Firing search from parent class..."); | |
return super.search(searchContext); | |
} | |
@Override | |
protected void doDelete(Object obj) throws Exception | |
{ | |
_log.info("*** doDelete"); | |
} | |
@Override | |
protected Document doGetDocument(Object obj) throws Exception | |
{ | |
_log.info("*** doGetDocument"); | |
return null; | |
} | |
@Override | |
protected Summary doGetSummary(Document document, Locale locale, String snippet, PortletURL portletURL) throws Exception | |
{ | |
_log.info("*** doGetSummary"); | |
return null; | |
} | |
@Override | |
protected void doReindex(Object obj) throws Exception | |
{ | |
_log.info("*** doReindex - just object"); | |
} | |
@Override | |
protected void doReindex(String className, long classPK) throws Exception | |
{ | |
_log.info("*** doReindex - classname and classpk"); | |
} | |
@Override | |
protected void doReindex(String[] ids) throws Exception | |
{ | |
_log.info("*** doGetDocument - string[]"); | |
} | |
@Override | |
protected String getPortletId(SearchContext searchContext) | |
{ | |
_log.info("*** getPortletId"); | |
return null; | |
} | |
} | |
3. Save and close the file. | |
--------------------------------------------------------------------------------------------------------- | |
STEP #7: Configure the Indexer Class | |
--------------------------------------------------------------------------------------------------------- | |
1. Open the WEB-INF/lifery-portlet.xml file and make the contentst the following -- | |
<?xml version="1.0"?> | |
<!DOCTYPE liferay-portlet-app PUBLIC "-//Liferay//DTD Portlet Application 6.2.0//EN" "http://www.liferay.com/dtd/liferay-portlet-app_6_2_0.dtd"> | |
<liferay-portlet-app> | |
<portlet> | |
<portlet-name>sample-recipe</portlet-name> | |
<icon>/icon.png</icon> | |
<indexer-class>com.devlife.example.liferay.portlet.search.RecipeIndexer</indexer-class> | |
<header-portlet-css>/css/main.css</header-portlet-css> | |
<footer-portlet-javascript>/js/main.js</footer-portlet-javascript> | |
<css-class-wrapper>sample-recipe-portlet</css-class-wrapper> | |
</portlet> | |
<role-mapper> | |
<role-name>user</role-name> | |
<role-link>User</role-link> | |
</role-mapper> | |
</liferay-portlet-app> | |
2. Save and close the file. | |
--------------------------------------------------------------------------------------------------------- | |
STEP #8: Validate the Indexer is loading | |
--------------------------------------------------------------------------------------------------------- | |
1. Open the RecipePortlet.java class and add the following render method -- | |
@Override | |
public void render(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException, IOException | |
{ | |
List<Indexer> indexers = IndexerRegistryUtil.getIndexers(); | |
for ( Indexer i : indexers ) | |
{ | |
_log.info("portlet id: " + i.getPortletId()); | |
_log.info("class: " + i.getClass() ); | |
} | |
super.render(renderRequest, renderResponse); | |
} | |
2. Save and close the file. | |
3. Deploy the new version of the portlet | |
4. Go to the reciepes page and reload it. | |
5. Check the log to validate that our indexer class is there. | |
18:37:29,078 INFO [http-bio-8080-exec-11][RecipePortlet:62] portlet id: samplerecipe_WAR_samplerecipeportlet | |
18:37:29,079 INFO [http-bio-8080-exec-11][RecipePortlet:63] class: class com.sun.proxy.$Proxy762 | |
Proxy shows up because the class is loaded dynamically. If you stop at the right point with a debugger you would be able to see that the implementation class is the RecipeIndexer we defined. | |
--------------------------------------------------------------------------------------------------------- | |
STEP #9: Adding a search method | |
--------------------------------------------------------------------------------------------------------- | |
1. Open the RecipeLocalServiceImpl file and add the following -- | |
public Hits search(long companyId, String title, String description, String prepTime, String cookTime, boolean andSearch, int start, int end, Sort sort) throws SystemException | |
{ | |
try | |
{ | |
SearchContext searchContext = new SearchContext(); | |
searchContext.setAndSearch(andSearch); | |
Map<String, Serializable> attributes = new HashMap<String, Serializable>(); | |
attributes.put("title", title); | |
attributes.put("description", description); | |
attributes.put("prepTime", prepTime); | |
attributes.put("cookTime", cookTime); | |
searchContext.setAttributes(attributes); | |
searchContext.setCompanyId(companyId); | |
searchContext.setEnd(end); | |
QueryConfig queryConfig = new QueryConfig(); | |
queryConfig.setHighlightEnabled(false); | |
queryConfig.setScoreEnabled(false); | |
searchContext.setQueryConfig(queryConfig); | |
if (sort != null) | |
searchContext.setSorts(sort); | |
searchContext.setStart(start); | |
Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(Recipe.class); | |
System.out.println("INDEXER: " + indexer); | |
return indexer.search(searchContext); | |
} | |
catch (Exception e) | |
{ | |
throw new SystemException(e); | |
} | |
} | |
2. Run the ANT build-service target to update the LocalServiceUtil class | |
3. Update the RecipePortlet to test it out. Change the render method to be defined as -- | |
@Override | |
public void render(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException, IOException | |
{ | |
List<Indexer> indexers = IndexerRegistryUtil.getIndexers(); | |
for ( Indexer i : indexers ) | |
{ | |
_log.info("portlet id: " + i.getPortletId()); | |
_log.info("class: " + i.getClass().getCanonicalName() ); | |
} | |
long companyId = PortalUtil.getCompanyId(renderRequest); | |
String title = "Spaghetti"; | |
String description = StringPool.BLANK; | |
String prepTime = StringPool.BLANK; | |
String cookTime = StringPool.BLANK; | |
boolean andSearch = true; | |
int start = 0; | |
int end = 100; | |
Sort sort = null; | |
try | |
{ | |
Hits hits = RecipeLocalServiceUtil.search(companyId, title, description, prepTime, cookTime, andSearch, start, end, sort); | |
} | |
catch (SystemException e) | |
{ | |
_log.error("Recipe search failed.", e ); | |
} | |
super.render(renderRequest, renderResponse); | |
} | |
4. Save and close the file | |
5. Deploy the new version of the portlet | |
6. Go to the Recipes page and refresh -- in the log you should see | |
INDEXER: com.devlife.example.liferay.portlet.search.RecipeIndexer@36268742 | |
20:20:44,625 INFO [http-bio-8080-exec-44][RecipeIndexer:52] ** Firing search from parent class... | |
Which is a line from out "search" method added to Service Builder classes and a line from our RecipeIndexer class. | |
--------------------------------------------------------------------------------------------------------- | |
STEP #10: Augmenting the ADD actions | |
--------------------------------------------------------------------------------------------------------- | |
1. Open the RecipeLocalServiceImpl java file and add the following method -- | |
@Override | |
@Indexable(type = IndexableType.REINDEX) | |
public Recipe addRecipe(Recipe recipe, ServiceContext serviceContext) throws SystemException | |
{ | |
Recipe r = super.addRecipe(recipe); | |
serviceContext.setIndexingEnabled(Boolean.TRUE); | |
r.setUuid(serviceContext.getUuid()); | |
if ((serviceContext == null) || serviceContext.isIndexingEnabled()) { | |
Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(Recipe.class); | |
try | |
{ | |
indexer.reindex(r); | |
} | |
catch (SearchException e) | |
{ | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
} | |
return r; | |
} | |
2. Save and close the file. | |
3. Rebuild the services | |
4. Deploy the new version of the portlet | |
5. Go to the Recipes page and add a new recipe. Check the log -- | |
13:13:50,669 INFO [http-bio-8080-exec-100][RecipeIndexer:92] *** doReindex - just object | |
So now we know our indexer will get called everytime we add a recipe. | |
--------------------------------------------------------------------------------------------------------- | |
STEP #11: RecipeIndexer Definition | |
--------------------------------------------------------------------------------------------------------- | |
1. Create a Recipe com.liferay.sample.service.persistence.RecipeActionableDynamicQuery class and place the following code into the file. | |
package com.liferay.sample.service.persistence; | |
import com.liferay.portal.kernel.dao.orm.BaseActionableDynamicQuery; | |
import com.liferay.portal.kernel.exception.SystemException; | |
import com.liferay.portal.kernel.util.PortalClassLoaderUtil; | |
import com.liferay.sample.model.Recipe; | |
import com.liferay.sample.service.RecipeLocalServiceUtil; | |
public abstract class RecipeActionableDynamicQuery extends BaseActionableDynamicQuery | |
{ | |
public RecipeActionableDynamicQuery() throws SystemException | |
{ | |
setBaseLocalService(RecipeLocalServiceUtil.getService()); | |
setClass(Recipe.class); | |
setClassLoader(PortalClassLoaderUtil.getClassLoader()); | |
setPrimaryKeyPropertyName("recipeId"); | |
} | |
} | |
2. Save and close the file. | |
3. Open the RecipeIndex file and replace the contents with this -- | |
package com.devlife.example.liferay.portlet.search; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Locale; | |
import java.util.Map; | |
import javax.portlet.PortletURL; | |
import com.liferay.portal.kernel.dao.orm.ActionableDynamicQuery; | |
import com.liferay.portal.kernel.exception.PortalException; | |
import com.liferay.portal.kernel.log.Log; | |
import com.liferay.portal.kernel.log.LogFactoryUtil; | |
import com.liferay.portal.kernel.search.BaseIndexer; | |
import com.liferay.portal.kernel.search.Document; | |
import com.liferay.portal.kernel.search.Field; | |
import com.liferay.portal.kernel.search.SearchContext; | |
import com.liferay.portal.kernel.search.SearchEngineUtil; | |
import com.liferay.portal.kernel.search.Summary; | |
import com.liferay.portal.kernel.util.GetterUtil; | |
import com.liferay.portal.kernel.util.LocaleUtil; | |
import com.liferay.portal.kernel.util.StringPool; | |
import com.liferay.portal.kernel.util.StringUtil; | |
import com.liferay.portal.kernel.util.Validator; | |
import com.liferay.portal.kernel.workflow.WorkflowConstants; | |
import com.liferay.portal.service.persistence.OrganizationActionableDynamicQuery; | |
import com.liferay.sample.model.Recipe; | |
import com.liferay.sample.service.RecipeLocalServiceUtil; | |
public class RecipeIndexer extends BaseIndexer | |
{ | |
// class logger | |
private static final Log _log = LogFactoryUtil.getLog(RecipeIndexer.class); | |
public static final String[] CLASS_NAMES = { Recipe.class.getName() }; | |
public static final String PORTLET_ID = "samplerecipe_WAR_samplerecipeportlet"; | |
@Override | |
public String[] getClassNames() | |
{ | |
return CLASS_NAMES; | |
} | |
@Override | |
public String getPortletId() | |
{ | |
return PORTLET_ID; | |
} | |
@Override | |
protected void doDelete(Object obj) throws Exception | |
{ | |
Recipe recipe = (Recipe) obj; | |
deleteDocument(recipe.getCompanyId(), recipe.getRecipeId()); | |
} | |
@Override | |
protected Document doGetDocument(Object obj) throws Exception | |
{ | |
Recipe recipe = (Recipe) obj; | |
Locale defaultLocale = LocaleUtil.getSiteDefault(); | |
String languageId = LocaleUtil.toLanguageId(defaultLocale); | |
Document document = newDocument(); | |
document.addUID(getPortletId(), recipe.getUuid()); | |
document.addText(Field.ENTRY_CLASS_NAME, getClassNames() ); | |
document.addNumber(Field.STATUS, WorkflowConstants.STATUS_APPROVED); | |
document.addNumber(Field.COMPANY_ID, recipe.getCompanyId()); | |
document.addNumber(Field.GROUP_ID, recipe.getGroupId()); | |
document.addDate(Field.CREATE_DATE, recipe.getCreateDate()); | |
document.addDate(Field.MODIFIED_DATE, recipe.getModifiedDate()); | |
document.addKeyword("recipeId", recipe.getRecipeId()); | |
document.addText(Field.TITLE, recipe.getTitle()); | |
document.addText("summary", recipe.getSummary()); | |
document.addText(Field.DESCRIPTION, recipe.getDescription()); | |
document.addText(Field.CONTENT, recipe.getDescription()); | |
document.addText(Field.CONTENT.concat(StringPool.UNDERLINE).concat(languageId),recipe.getDescription()); | |
document.addText(Field.DESCRIPTION.concat(StringPool.UNDERLINE).concat(languageId), recipe.getDescription()); | |
document.addText(Field.TITLE.concat(StringPool.UNDERLINE).concat(languageId), recipe.getTitle()); | |
document.addKeyword("servings", recipe.getServings()); | |
document.addText("prepTime", Integer.toString(recipe.getPrepTime())); | |
document.addText("cookTime", Integer.toString(recipe.getCookTime())); | |
document.addText("ingredients", recipe.getIngredients()); | |
document.addText("defaultLanguageId", languageId); | |
return document; | |
} | |
@Override | |
protected Summary doGetSummary(Document document, Locale locale, String snippet, PortletURL portletURL) throws Exception | |
{ | |
Locale snippetLocale = getSnippetLocale(document, locale); | |
if (snippetLocale == null) { | |
snippetLocale = LocaleUtil.fromLanguageId( | |
document.get("defaultLanguageId")); | |
} | |
String prefix = Field.SNIPPET + StringPool.UNDERLINE; | |
String title = document.get(snippetLocale, prefix + Field.TITLE, Field.TITLE); | |
String content = document.get(snippetLocale, prefix + Field.CONTENT, Field.CONTENT); | |
String recipeId = document.get("recipeId"); | |
portletURL.setParameter("recipeId", recipeId); | |
return new Summary(snippetLocale, title, content, portletURL); | |
} | |
@Override | |
protected void doReindex(Object obj) throws Exception | |
{ | |
if (obj instanceof List<?>) | |
{ | |
List<Recipe> recipes = (List<Recipe>) obj; | |
for (Recipe recipe : recipes) | |
{ | |
doReindex(recipe); | |
} | |
} | |
else if (obj instanceof Long) | |
{ | |
long recipeId = (Long) obj; | |
Recipe recipe = RecipeLocalServiceUtil.getRecipe(recipeId); | |
doReindex(recipe); | |
} | |
else if (obj instanceof long[]) | |
{ | |
long[] recipeIds = (long[]) obj; | |
Map<Long, Collection<Document>> documentsMap = new HashMap<Long, Collection<Document>>(); | |
for (long recipeId : recipeIds) | |
{ | |
Recipe recipe = RecipeLocalServiceUtil.fetchRecipe(recipeId); | |
if (recipe == null) | |
{ | |
continue; | |
} | |
Document document = getDocument(recipe); | |
long companyId = recipe.getCompanyId(); | |
Collection<Document> documents = documentsMap.get(companyId); | |
if (documents == null) | |
{ | |
documents = new ArrayList<Document>(); | |
documentsMap.put(companyId, documents); | |
} | |
documents.add(document); | |
} | |
for (Map.Entry<Long, Collection<Document>> entry : documentsMap.entrySet()) | |
{ | |
long companyId = entry.getKey(); | |
Collection<Document> documents = entry.getValue(); | |
SearchEngineUtil.updateDocuments(getSearchEngineId(), companyId, documents); | |
} | |
} | |
else if (obj instanceof Recipe) | |
{ | |
Recipe recipe = (Recipe) obj; | |
Document document = getDocument(recipe); | |
SearchEngineUtil.updateDocument(getSearchEngineId(), recipe.getCompanyId(), document); | |
} | |
} | |
@Override | |
protected void doReindex(String className, long classPK) throws Exception | |
{ | |
Recipe recipe = RecipeLocalServiceUtil.getRecipe(classPK); | |
doReindex(recipe); | |
} | |
@Override | |
protected void doReindex(String[] ids) throws Exception | |
{ | |
long recipeId = GetterUtil.getLong(ids[0]); | |
reindexRecipes(recipeId); | |
} | |
@Override | |
protected String getPortletId(SearchContext searchContext) | |
{ | |
return this.PORTLET_ID; | |
} | |
protected void reindexRecipes(long companyId) throws Exception | |
{ | |
ActionableDynamicQuery actionableDynamicQuery = new OrganizationActionableDynamicQuery() | |
{ | |
@Override | |
protected void performAction(Object object) throws PortalException | |
{ | |
Recipe recipe = (Recipe) object; | |
Document document = getDocument(recipe); | |
addDocument(document); | |
} | |
}; | |
actionableDynamicQuery.setCompanyId(companyId); | |
actionableDynamicQuery.setSearchEngineId(getSearchEngineId()); | |
actionableDynamicQuery.performActions(); | |
} | |
protected String getBasicContentSummary( | |
Document document, Locale snippetLocale) { | |
String prefix = Field.SNIPPET + StringPool.UNDERLINE; | |
String content = document.get( | |
snippetLocale, prefix + Field.DESCRIPTION, prefix + Field.CONTENT); | |
if (Validator.isBlank(content)) { | |
content = document.get( | |
snippetLocale, Field.DESCRIPTION, Field.CONTENT); | |
} | |
if (content.length() > 200) { | |
content = StringUtil.shorten(content, 200); | |
} | |
return content; | |
} | |
} | |
4. Save and close the file. | |
5. Deploy the new version of your portlet. | |
6. Go to the browser and add a few recipes. | |
--------------------------------------------------------------------------------------------------------- | |
STEP #12: Checking your results with LUKE | |
--------------------------------------------------------------------------------------------------------- | |
1. Start luke | |
2. Go to the data/lucene folder and find the folder with your company ID | |
3. Select the .fdx file | |
4. Choose open read only and force unlock | |
5. Click on the search tab and enter *:* for the query | |
6. Change the expression to be entryClassName:com.liferay.sample.model.Recipe | |
7. You should see your records. | |
--------------------------------------------------------------------------------------------------------- | |
STEP #13: Federated search portlet | |
--------------------------------------------------------------------------------------------------------- | |
Note: Add web content for Recipes first, 2 or three items and show that working with Search portlet, then perform steps below. | |
1. Go to the Recipes page (make sure you are logged in as an admin) | |
2. Add the search portlet to the page. | |
3. Go to the "Configuration" for the search portlet | |
4. Click Advanced | |
5. Remove the Asset Entry filter | |
6. Enable the query display (bottom of configuration window) | |
7. Search for your recipe and you should see it in the results. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment