001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.usersadmin.util;
016    
017    import com.liferay.portal.NoSuchContactException;
018    import com.liferay.portal.kernel.dao.orm.ActionableDynamicQuery;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.search.BaseIndexer;
021    import com.liferay.portal.kernel.search.BooleanClauseOccur;
022    import com.liferay.portal.kernel.search.BooleanQuery;
023    import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
024    import com.liferay.portal.kernel.search.Document;
025    import com.liferay.portal.kernel.search.Field;
026    import com.liferay.portal.kernel.search.Indexer;
027    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
028    import com.liferay.portal.kernel.search.SearchContext;
029    import com.liferay.portal.kernel.search.SearchEngineUtil;
030    import com.liferay.portal.kernel.search.Summary;
031    import com.liferay.portal.kernel.util.ArrayUtil;
032    import com.liferay.portal.kernel.util.GetterUtil;
033    import com.liferay.portal.kernel.util.Validator;
034    import com.liferay.portal.kernel.workflow.WorkflowConstants;
035    import com.liferay.portal.model.Contact;
036    import com.liferay.portal.model.Organization;
037    import com.liferay.portal.model.User;
038    import com.liferay.portal.model.impl.ContactImpl;
039    import com.liferay.portal.security.auth.FullNameGenerator;
040    import com.liferay.portal.security.auth.FullNameGeneratorFactory;
041    import com.liferay.portal.service.OrganizationLocalServiceUtil;
042    import com.liferay.portal.service.UserLocalServiceUtil;
043    import com.liferay.portal.util.PortletKeys;
044    import com.liferay.portal.util.PropsValues;
045    
046    import java.util.ArrayList;
047    import java.util.Collection;
048    import java.util.HashMap;
049    import java.util.HashSet;
050    import java.util.LinkedHashMap;
051    import java.util.Locale;
052    import java.util.Map;
053    import java.util.Set;
054    
055    import javax.portlet.PortletRequest;
056    import javax.portlet.PortletResponse;
057    import javax.portlet.PortletURL;
058    
059    /**
060     * @author Raymond Aug??
061     * @author Zsigmond Rab
062     * @author Hugo Huijser
063     */
064    public class UserIndexer extends BaseIndexer {
065    
066            public static final String[] CLASS_NAMES = {User.class.getName()};
067    
068            public static final String PORTLET_ID = PortletKeys.USERS_ADMIN;
069    
070            public UserIndexer() {
071                    setCommitImmediately(true);
072                    setDefaultSelectedFieldNames(
073                            Field.COMPANY_ID, Field.UID, Field.USER_ID);
074                    setIndexerEnabled(PropsValues.USERS_INDEXER_ENABLED);
075                    setPermissionAware(true);
076                    setStagingAware(false);
077            }
078    
079            @Override
080            public String[] getClassNames() {
081                    return CLASS_NAMES;
082            }
083    
084            @Override
085            public String getPortletId() {
086                    return PORTLET_ID;
087            }
088    
089            @Override
090            public void postProcessContextQuery(
091                            BooleanQuery contextQuery, SearchContext searchContext)
092                    throws Exception {
093    
094                    int status = GetterUtil.getInteger(
095                            searchContext.getAttribute(Field.STATUS),
096                            WorkflowConstants.STATUS_APPROVED);
097    
098                    if (status != WorkflowConstants.STATUS_ANY) {
099                            contextQuery.addRequiredTerm(Field.STATUS, status);
100                    }
101    
102                    LinkedHashMap<String, Object> params =
103                            (LinkedHashMap<String, Object>)searchContext.getAttribute("params");
104    
105                    if (params == null) {
106                            return;
107                    }
108    
109                    for (Map.Entry<String, Object> entry : params.entrySet()) {
110                            String key = entry.getKey();
111                            Object value = entry.getValue();
112    
113                            if (value == null) {
114                                    continue;
115                            }
116    
117                            Class<?> clazz = value.getClass();
118    
119                            if (clazz.isArray()) {
120                                    Object[] values = (Object[])value;
121    
122                                    if (values.length == 0) {
123                                            continue;
124                                    }
125                            }
126    
127                            addContextQueryParams(contextQuery, searchContext, key, value);
128                    }
129            }
130    
131            @Override
132            public void postProcessSearchQuery(
133                            BooleanQuery searchQuery, SearchContext searchContext)
134                    throws Exception {
135    
136                    addSearchTerm(searchQuery, searchContext, "city", false);
137                    addSearchTerm(searchQuery, searchContext, "country", false);
138                    addSearchTerm(searchQuery, searchContext, "emailAddress", false);
139                    addSearchTerm(searchQuery, searchContext, "firstName", false);
140                    addSearchTerm(searchQuery, searchContext, "fullName", false);
141                    addSearchTerm(searchQuery, searchContext, "lastName", false);
142                    addSearchTerm(searchQuery, searchContext, "middleName", false);
143                    addSearchTerm(searchQuery, searchContext, "region", false);
144                    addSearchTerm(searchQuery, searchContext, "screenName", false);
145                    addSearchTerm(searchQuery, searchContext, "street", false);
146                    addSearchTerm(searchQuery, searchContext, "zip", false);
147    
148                    LinkedHashMap<String, Object> params =
149                            (LinkedHashMap<String, Object>)searchContext.getAttribute("params");
150    
151                    if (params != null) {
152                            String expandoAttributes = (String)params.get("expandoAttributes");
153    
154                            if (Validator.isNotNull(expandoAttributes)) {
155                                    addSearchExpando(searchQuery, searchContext, expandoAttributes);
156                            }
157                    }
158            }
159    
160            protected void addContextQueryParams(
161                            BooleanQuery contextQuery, SearchContext searchContext, String key,
162                            Object value)
163                    throws Exception {
164    
165                    if (key.equals("usersGroups")) {
166                            if (value instanceof Long[]) {
167                                    Long[] values = (Long[])value;
168    
169                                    BooleanQuery usersGroupsQuery = BooleanQueryFactoryUtil.create(
170                                            searchContext);
171    
172                                    for (long groupId : values) {
173                                            usersGroupsQuery.addTerm("groupIds", groupId);
174                                    }
175    
176                                    contextQuery.add(usersGroupsQuery, BooleanClauseOccur.MUST);
177                            }
178                            else {
179                                    contextQuery.addRequiredTerm("groupIds", String.valueOf(value));
180                            }
181                    }
182                    else if (key.equals("usersOrgs")) {
183                            if (value instanceof Long[]) {
184                                    Long[] values = (Long[])value;
185    
186                                    BooleanQuery usersOrgsQuery = BooleanQueryFactoryUtil.create(
187                                            searchContext);
188    
189                                    for (long organizationId : values) {
190                                            usersOrgsQuery.addTerm("organizationIds", organizationId);
191                                            usersOrgsQuery.addTerm(
192                                                    "ancestorOrganizationIds", organizationId);
193                                    }
194    
195                                    contextQuery.add(usersOrgsQuery, BooleanClauseOccur.MUST);
196                            }
197                            else {
198                                    contextQuery.addRequiredTerm(
199                                            "organizationIds", String.valueOf(value));
200                            }
201                    }
202                    else if (key.equals("usersOrgsCount")) {
203                            contextQuery.addRequiredTerm(
204                                    "organizationCount", String.valueOf(value));
205                    }
206                    else if (key.equals("usersRoles")) {
207                            contextQuery.addRequiredTerm("roleIds", String.valueOf(value));
208                    }
209                    else if (key.equals("usersTeams")) {
210                            contextQuery.addRequiredTerm("teamIds", String.valueOf(value));
211                    }
212                    else if (key.equals("usersUserGroups")) {
213                            contextQuery.addRequiredTerm("userGroupIds", String.valueOf(value));
214                    }
215            }
216    
217            @Override
218            protected void doDelete(Object obj) throws Exception {
219                    User user = (User)obj;
220    
221                    deleteDocument(user.getCompanyId(), user.getUserId());
222    
223                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(Contact.class);
224    
225                    Contact contact = new ContactImpl();
226    
227                    contact.setContactId(user.getContactId());
228                    contact.setCompanyId(user.getCompanyId());
229    
230                    indexer.delete(contact);
231            }
232    
233            @Override
234            protected Document doGetDocument(Object obj) throws Exception {
235                    User user = (User)obj;
236    
237                    Document document = getBaseModelDocument(PORTLET_ID, user);
238    
239                    long[] organizationIds = user.getOrganizationIds();
240    
241                    document.addKeyword(Field.COMPANY_ID, user.getCompanyId());
242                    document.addKeyword(Field.GROUP_ID, user.getGroupIds());
243                    document.addDate(Field.MODIFIED_DATE, user.getModifiedDate());
244                    document.addKeyword(Field.SCOPE_GROUP_ID, user.getGroupIds());
245                    document.addKeyword(Field.STATUS, user.getStatus());
246                    document.addKeyword(Field.USER_ID, user.getUserId());
247                    document.addKeyword(Field.USER_NAME, user.getFullName());
248    
249                    document.addKeyword(
250                            "ancestorOrganizationIds",
251                            getAncestorOrganizationIds(user.getOrganizationIds()));
252                    document.addText("emailAddress", user.getEmailAddress());
253                    document.addText("firstName", user.getFirstName());
254                    document.addText("fullName", user.getFullName());
255                    document.addKeyword("groupIds", user.getGroupIds());
256                    document.addText("jobTitle", user.getJobTitle());
257                    document.addText("lastName", user.getLastName());
258                    document.addText("middleName", user.getMiddleName());
259                    document.addKeyword("organizationIds", organizationIds);
260                    document.addKeyword(
261                            "organizationCount", String.valueOf(organizationIds.length));
262                    document.addKeyword("roleIds", user.getRoleIds());
263                    document.addText("screenName", user.getScreenName());
264                    document.addKeyword("teamIds", user.getTeamIds());
265                    document.addKeyword("userGroupIds", user.getUserGroupIds());
266    
267                    populateAddresses(document, user.getAddresses(), 0, 0);
268    
269                    return document;
270            }
271    
272            @Override
273            protected String doGetSortField(String orderByCol) {
274                    if (orderByCol.equals("email-address")) {
275                            return "emailAddress";
276                    }
277                    else if (orderByCol.equals("first-name")) {
278                            return "firstName";
279                    }
280                    else if (orderByCol.equals("job-title")) {
281                            return "jobTitle";
282                    }
283                    else if (orderByCol.equals("last-name")) {
284                            return "lastName";
285                    }
286                    else if (orderByCol.equals("screen-name")) {
287                            return "screenName";
288                    }
289                    else {
290                            return orderByCol;
291                    }
292            }
293    
294            @Override
295            protected Summary doGetSummary(
296                    Document document, Locale locale, String snippet, PortletURL portletURL,
297                    PortletRequest portletRequest, PortletResponse portletResponse) {
298    
299                    String firstName = document.get("firstName");
300                    String middleName = document.get("middleName");
301                    String lastName = document.get("lastName");
302    
303                    FullNameGenerator fullNameGenerator =
304                            FullNameGeneratorFactory.getInstance();
305    
306                    String title = fullNameGenerator.getFullName(
307                            firstName, middleName, lastName);
308    
309                    String content = null;
310    
311                    String userId = document.get(Field.USER_ID);
312    
313                    portletURL.setParameter("struts_action", "/users_admin/edit_user");
314                    portletURL.setParameter("p_u_i_d", userId);
315    
316                    return new Summary(title, content, portletURL);
317            }
318    
319            @Override
320            protected void doReindex(Object obj) throws Exception {
321                    if (obj instanceof Long) {
322                            long userId = (Long)obj;
323    
324                            User user = UserLocalServiceUtil.getUserById(userId);
325    
326                            doReindex(user);
327                    }
328                    else if (obj instanceof long[]) {
329                            long[] userIds = (long[])obj;
330    
331                            Map<Long, Collection<Document>> documentsMap =
332                                    new HashMap<Long, Collection<Document>>();
333    
334                            for (long userId : userIds) {
335                                    User user = UserLocalServiceUtil.getUserById(userId);
336    
337                                    if (user.isDefaultUser()) {
338                                            continue;
339                                    }
340    
341                                    Document document = getDocument(user);
342    
343                                    long companyId = user.getCompanyId();
344    
345                                    Collection<Document> documents = documentsMap.get(companyId);
346    
347                                    if (documents == null) {
348                                            documents = new ArrayList<Document>();
349    
350                                            documentsMap.put(companyId, documents);
351                                    }
352    
353                                    documents.add(document);
354                            }
355    
356                            for (Map.Entry<Long, Collection<Document>> entry :
357                                            documentsMap.entrySet()) {
358    
359                                    long companyId = entry.getKey();
360                                    Collection<Document> documents = entry.getValue();
361    
362                                    SearchEngineUtil.updateDocuments(
363                                            getSearchEngineId(), companyId, documents,
364                                            isCommitImmediately());
365                            }
366                    }
367                    else if (obj instanceof User) {
368                            User user = (User)obj;
369    
370                            if (user.isDefaultUser()) {
371                                    return;
372                            }
373    
374                            Document document = getDocument(user);
375    
376                            SearchEngineUtil.updateDocument(
377                                    getSearchEngineId(), user.getCompanyId(), document,
378                                    isCommitImmediately());
379    
380                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
381                                    Contact.class);
382    
383                            try {
384                                    indexer.reindex(user.getContact());
385                            }
386                            catch (NoSuchContactException nscce) {
387    
388                                    // This is a temporary workaround for LPS-46825
389    
390                            }
391                    }
392            }
393    
394            @Override
395            protected void doReindex(String className, long classPK) throws Exception {
396                    User user = UserLocalServiceUtil.getUserById(classPK);
397    
398                    doReindex(user);
399            }
400    
401            @Override
402            protected void doReindex(String[] ids) throws Exception {
403                    long companyId = GetterUtil.getLong(ids[0]);
404    
405                    reindexUsers(companyId);
406            }
407    
408            protected long[] getAncestorOrganizationIds(long[] organizationIds)
409                    throws Exception {
410    
411                    Set<Long> ancestorOrganizationIds = new HashSet<Long>();
412    
413                    for (long organizationId : organizationIds) {
414                            Organization organization =
415                                    OrganizationLocalServiceUtil.getOrganization(organizationId);
416    
417                            for (long ancestorOrganizationId :
418                                            organization.getAncestorOrganizationIds()) {
419    
420                                    ancestorOrganizationIds.add(ancestorOrganizationId);
421                            }
422                    }
423    
424                    return ArrayUtil.toLongArray(ancestorOrganizationIds);
425            }
426    
427            @Override
428            protected String getPortletId(SearchContext searchContext) {
429                    return PORTLET_ID;
430            }
431    
432            protected void reindexUsers(long companyId) throws PortalException {
433                    final ActionableDynamicQuery actionableDynamicQuery =
434                            UserLocalServiceUtil.getActionableDynamicQuery();
435    
436                    actionableDynamicQuery.setCompanyId(companyId);
437                    actionableDynamicQuery.setPerformActionMethod(
438                            new ActionableDynamicQuery.PerformActionMethod() {
439    
440                                    @Override
441                                    public void performAction(Object object)
442                                            throws PortalException {
443    
444                                            User user = (User)object;
445    
446                                            if (!user.isDefaultUser()) {
447                                                    Document document = getDocument(user);
448    
449                                                    actionableDynamicQuery.addDocument(document);
450                                            }
451                                    }
452    
453                            });
454                    actionableDynamicQuery.setSearchEngineId(getSearchEngineId());
455    
456                    actionableDynamicQuery.performActions();
457            }
458    
459    }