Skip to content

Instantly share code, notes, and snippets.

@jardineworks
Last active November 1, 2017 22:45
Show Gist options
  • Save jardineworks/eb9e39290536ef0efd3c to your computer and use it in GitHub Desktop.
Save jardineworks/eb9e39290536ef0efd3c to your computer and use it in GitHub Desktop.
SB + Custom Indexer + Search
---------------------------------------------------------------------------------------------------------
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