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.portal.service.impl;
016    
017    import com.liferay.portal.DuplicateOrganizationException;
018    import com.liferay.portal.OrganizationNameException;
019    import com.liferay.portal.OrganizationParentException;
020    import com.liferay.portal.OrganizationTypeException;
021    import com.liferay.portal.RequiredOrganizationException;
022    import com.liferay.portal.kernel.configuration.Filter;
023    import com.liferay.portal.kernel.dao.orm.QueryUtil;
024    import com.liferay.portal.kernel.exception.PortalException;
025    import com.liferay.portal.kernel.exception.SystemException;
026    import com.liferay.portal.kernel.search.BaseModelSearchResult;
027    import com.liferay.portal.kernel.search.Hits;
028    import com.liferay.portal.kernel.search.Indexer;
029    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
030    import com.liferay.portal.kernel.search.QueryConfig;
031    import com.liferay.portal.kernel.search.SearchContext;
032    import com.liferay.portal.kernel.search.SearchException;
033    import com.liferay.portal.kernel.search.Sort;
034    import com.liferay.portal.kernel.systemevent.SystemEvent;
035    import com.liferay.portal.kernel.util.ArrayUtil;
036    import com.liferay.portal.kernel.util.GetterUtil;
037    import com.liferay.portal.kernel.util.ListUtil;
038    import com.liferay.portal.kernel.util.MapUtil;
039    import com.liferay.portal.kernel.util.OrderByComparator;
040    import com.liferay.portal.kernel.util.PropsKeys;
041    import com.liferay.portal.kernel.util.SetUtil;
042    import com.liferay.portal.kernel.util.StringPool;
043    import com.liferay.portal.kernel.util.StringUtil;
044    import com.liferay.portal.kernel.util.TreeModelTasksAdapter;
045    import com.liferay.portal.kernel.util.TreePathUtil;
046    import com.liferay.portal.kernel.util.Validator;
047    import com.liferay.portal.kernel.workflow.WorkflowConstants;
048    import com.liferay.portal.model.Company;
049    import com.liferay.portal.model.Country;
050    import com.liferay.portal.model.Group;
051    import com.liferay.portal.model.GroupConstants;
052    import com.liferay.portal.model.ListTypeConstants;
053    import com.liferay.portal.model.Organization;
054    import com.liferay.portal.model.OrganizationConstants;
055    import com.liferay.portal.model.Region;
056    import com.liferay.portal.model.ResourceConstants;
057    import com.liferay.portal.model.Role;
058    import com.liferay.portal.model.RoleConstants;
059    import com.liferay.portal.model.SystemEventConstants;
060    import com.liferay.portal.model.User;
061    import com.liferay.portal.model.UserGroupRole;
062    import com.liferay.portal.model.impl.OrganizationImpl;
063    import com.liferay.portal.security.permission.PermissionCacheUtil;
064    import com.liferay.portal.service.ServiceContext;
065    import com.liferay.portal.service.base.OrganizationLocalServiceBaseImpl;
066    import com.liferay.portal.util.PortalUtil;
067    import com.liferay.portal.util.PrefsPropsUtil;
068    import com.liferay.portal.util.PropsUtil;
069    import com.liferay.portal.util.PropsValues;
070    import com.liferay.portal.util.comparator.OrganizationIdComparator;
071    import com.liferay.portal.util.comparator.OrganizationNameComparator;
072    import com.liferay.portlet.usersadmin.util.UsersAdminUtil;
073    import com.liferay.util.dao.orm.CustomSQLUtil;
074    
075    import java.io.Serializable;
076    
077    import java.util.ArrayList;
078    import java.util.Collections;
079    import java.util.HashMap;
080    import java.util.HashSet;
081    import java.util.Iterator;
082    import java.util.LinkedHashMap;
083    import java.util.List;
084    import java.util.Map;
085    import java.util.Set;
086    
087    /**
088     * Provides the local service for accessing, adding, deleting, and updating
089     * organizations.
090     *
091     * @author Brian Wing Shun Chan
092     * @author Jorge Ferrer
093     * @author Julio Camarero
094     * @author Hugo Huijser
095     * @author Juan Fern??ndez
096     */
097    public class OrganizationLocalServiceImpl
098            extends OrganizationLocalServiceBaseImpl {
099    
100            /**
101             * Adds the organizations to the group.
102             *
103             * @param  groupId the primary key of the group
104             * @param  organizationIds the primary keys of the organizations
105             * @throws PortalException if a group or organization with the primary key
106             *         could not be found
107             */
108            @Override
109            public void addGroupOrganizations(long groupId, long[] organizationIds)
110                    throws PortalException {
111    
112                    groupPersistence.addOrganizations(groupId, organizationIds);
113    
114                    PermissionCacheUtil.clearCache();
115            }
116    
117            /**
118             * Adds an organization.
119             *
120             * <p>
121             * This method handles the creation and bookkeeping of the organization
122             * including its resources, metadata, and internal data structures. It is
123             * not necessary to make a subsequent call to {@link
124             * #addOrganizationResources(long, Organization)}.
125             * </p>
126             *
127             * @param  userId the primary key of the creator/owner of the organization
128             * @param  parentOrganizationId the primary key of the organization's parent
129             *         organization
130             * @param  name the organization's name
131             * @param  site whether the organization is to be associated with a main
132             *         site
133             * @return the organization
134             * @throws PortalException if a creator or parent organization with the
135             *         primary key could not be found or if the organization's
136             *         information was invalid
137             */
138            @Override
139            public Organization addOrganization(
140                            long userId, long parentOrganizationId, String name, boolean site)
141                    throws PortalException {
142    
143                    return addOrganization(
144                            userId, parentOrganizationId, name,
145                            OrganizationConstants.TYPE_REGULAR_ORGANIZATION, 0, 0,
146                            ListTypeConstants.ORGANIZATION_STATUS_DEFAULT, StringPool.BLANK,
147                            site, null);
148            }
149    
150            /**
151             * Adds an organization.
152             *
153             * <p>
154             * This method handles the creation and bookkeeping of the organization
155             * including its resources, metadata, and internal data structures. It is
156             * not necessary to make a subsequent call to {@link
157             * #addOrganizationResources(long, Organization)}.
158             * </p>
159             *
160             * @param      userId the primary key of the creator/owner of the
161             *             organization
162             * @param      parentOrganizationId the primary key of the organization's
163             *             parent organization
164             * @param      name the organization's name
165             * @param      type the organization's type
166             * @param      recursable whether the permissions of the organization are to
167             *             be inherited by its suborganizations
168             * @param      regionId the primary key of the organization's region
169             * @param      countryId the primary key of the organization's country
170             * @param      statusId the organization's workflow status
171             * @param      comments the comments about the organization
172             * @param      site whether the organization is to be associated with a main
173             *             site
174             * @param      serviceContext the service context to be applied (optionally
175             *             <code>null</code>). Can set asset category IDs, asset tag
176             *             names, and expando bridge attributes for the organization.
177             * @return     the organization
178             * @throws     PortalException if a creator or parent organization with the
179             *             primary key could not be found or if the organization's
180             *             information was invalid
181             * @deprecated As of 6.2.0, replaced by {@link #addOrganization(long, long,
182             *             String, String, long, long, int, String, boolean,
183             *             ServiceContext)}
184             */
185            @Deprecated
186            @Override
187            public Organization addOrganization(
188                            long userId, long parentOrganizationId, String name, String type,
189                            boolean recursable, long regionId, long countryId, long statusId,
190                            String comments, boolean site, ServiceContext serviceContext)
191                    throws PortalException {
192    
193                    return addOrganization(
194                            userId, parentOrganizationId, name, type, regionId, countryId,
195                            statusId, comments, site, serviceContext);
196            }
197    
198            /**
199             * Adds an organization.
200             *
201             * <p>
202             * This method handles the creation and bookkeeping of the organization
203             * including its resources, metadata, and internal data structures. It is
204             * not necessary to make a subsequent call to {@link
205             * #addOrganizationResources(long, Organization)}.
206             * </p>
207             *
208             * @param  userId the primary key of the creator/owner of the organization
209             * @param  parentOrganizationId the primary key of the organization's parent
210             *         organization
211             * @param  name the organization's name
212             * @param  type the organization's type
213             * @param  regionId the primary key of the organization's region
214             * @param  countryId the primary key of the organization's country
215             * @param  statusId the organization's workflow status
216             * @param  comments the comments about the organization
217             * @param  site whether the organization is to be associated with a main
218             *         site
219             * @param  serviceContext the service context to be applied (optionally
220             *         <code>null</code>). Can set asset category IDs, asset tag names,
221             *         and expando bridge attributes for the organization.
222             * @return the organization
223             * @throws PortalException if a creator or parent organization with the
224             *         primary key could not be found or if the organization's
225             *         information was invalid
226             */
227            @Override
228            public Organization addOrganization(
229                            long userId, long parentOrganizationId, String name, String type,
230                            long regionId, long countryId, long statusId, String comments,
231                            boolean site, ServiceContext serviceContext)
232                    throws PortalException {
233    
234                    // Organization
235    
236                    User user = userPersistence.findByPrimaryKey(userId);
237                    parentOrganizationId = getParentOrganizationId(
238                            user.getCompanyId(), parentOrganizationId);
239    
240                    validate(
241                            user.getCompanyId(), parentOrganizationId, name, type, countryId,
242                            statusId);
243    
244                    long organizationId = counterLocalService.increment();
245    
246                    Organization organization = organizationPersistence.create(
247                            organizationId);
248    
249                    if (serviceContext != null) {
250                            organization.setUuid(serviceContext.getUuid());
251                    }
252    
253                    organization.setCompanyId(user.getCompanyId());
254                    organization.setUserId(user.getUserId());
255                    organization.setUserName(user.getFullName());
256                    organization.setParentOrganizationId(parentOrganizationId);
257                    organization.setTreePath(organization.buildTreePath());
258                    organization.setName(name);
259                    organization.setType(type);
260                    organization.setRecursable(true);
261                    organization.setRegionId(regionId);
262                    organization.setCountryId(countryId);
263                    organization.setStatusId(statusId);
264                    organization.setComments(comments);
265                    organization.setExpandoBridgeAttributes(serviceContext);
266    
267                    organizationPersistence.update(organization);
268    
269                    // Group
270    
271                    long parentGroupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
272    
273                    if (parentOrganizationId !=
274                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
275    
276                            Organization parentOrganization =
277                                    organizationPersistence.fetchByPrimaryKey(parentOrganizationId);
278    
279                            if (parentOrganization != null) {
280                                    Group parentGroup = parentOrganization.getGroup();
281    
282                                    if (site && parentGroup.isSite()) {
283                                            parentGroupId = parentOrganization.getGroupId();
284                                    }
285                            }
286                    }
287    
288                    Group group = groupLocalService.addGroup(
289                            userId, parentGroupId, Organization.class.getName(), organizationId,
290                            GroupConstants.DEFAULT_LIVE_GROUP_ID, getLocalizationMap(name),
291                            null, GroupConstants.TYPE_SITE_PRIVATE, false,
292                            GroupConstants.DEFAULT_MEMBERSHIP_RESTRICTION, null, site, true,
293                            null);
294    
295                    // Role
296    
297                    Role role = roleLocalService.getRole(
298                            organization.getCompanyId(), RoleConstants.ORGANIZATION_OWNER);
299    
300                    userGroupRoleLocalService.addUserGroupRoles(
301                            userId, group.getGroupId(), new long[] {role.getRoleId()});
302    
303                    // Resources
304    
305                    addOrganizationResources(userId, organization);
306    
307                    // Asset
308    
309                    if (serviceContext != null) {
310                            updateAsset(
311                                    userId, organization, serviceContext.getAssetCategoryIds(),
312                                    serviceContext.getAssetTagNames());
313                    }
314    
315                    // Indexer
316    
317                    if ((serviceContext == null) || serviceContext.isIndexingEnabled()) {
318                            Indexer<Organization> indexer =
319                                    IndexerRegistryUtil.nullSafeGetIndexer(Organization.class);
320    
321                            indexer.reindex(organization);
322                    }
323    
324                    return organization;
325            }
326    
327            /**
328             * Adds a resource for each type of permission available on the
329             * organization.
330             *
331             * @param  userId the primary key of the creator/owner of the organization
332             * @param  organization the organization
333             * @throws PortalException if a portal exception occurred
334             */
335            @Override
336            public void addOrganizationResources(long userId, Organization organization)
337                    throws PortalException {
338    
339                    String name = Organization.class.getName();
340    
341                    resourceLocalService.addResources(
342                            organization.getCompanyId(), 0, userId, name,
343                            organization.getOrganizationId(), false, false, false);
344            }
345    
346            /**
347             * Assigns the password policy to the organizations, removing any other
348             * currently assigned password policies.
349             *
350             * @param passwordPolicyId the primary key of the password policy
351             * @param organizationIds the primary keys of the organizations
352             */
353            @Override
354            public void addPasswordPolicyOrganizations(
355                    long passwordPolicyId, long[] organizationIds) {
356    
357                    passwordPolicyRelLocalService.addPasswordPolicyRels(
358                            passwordPolicyId, Organization.class.getName(), organizationIds);
359            }
360    
361            /**
362             * Deletes the organization's logo.
363             *
364             * @param  organizationId the primary key of the organization
365             * @throws PortalException if an organization or parent organization with
366             *         the primary key could not be found or if the organization's logo
367             *         could not be found
368             */
369            @Override
370            public void deleteLogo(long organizationId) throws PortalException {
371                    Organization organization = getOrganization(organizationId);
372    
373                    PortalUtil.updateImageId(organization, false, null, "logoId", 0, 0, 0);
374            }
375    
376            /**
377             * Deletes the organization. The organization's associated resources and
378             * assets are also deleted.
379             *
380             * @param  organizationId the primary key of the organization
381             * @return the deleted organization
382             * @throws PortalException if an organization with the primary key could not
383             *         be found, if the organization had a workflow in approved status,
384             *         or if the organization was a parent organization
385             */
386            @Override
387            public Organization deleteOrganization(long organizationId)
388                    throws PortalException {
389    
390                    Organization organization = organizationPersistence.findByPrimaryKey(
391                            organizationId);
392    
393                    return organizationLocalService.deleteOrganization(organization);
394            }
395    
396            /**
397             * Deletes the organization. The organization's associated resources and
398             * assets are also deleted.
399             *
400             * @param  organization the organization
401             * @return the deleted organization
402             * @throws PortalException if the organization had a workflow in approved
403             *         status or if the organization was a parent organization
404             */
405            @Override
406            @SystemEvent(type = SystemEventConstants.TYPE_DELETE)
407            public Organization deleteOrganization(Organization organization)
408                    throws PortalException {
409    
410                    if ((userLocalService.getOrganizationUsersCount(
411                                    organization.getOrganizationId(),
412                                    WorkflowConstants.STATUS_APPROVED) > 0) ||
413                            (organizationPersistence.countByC_P(
414                                    organization.getCompanyId(),
415                                    organization.getOrganizationId()) > 0)) {
416    
417                            throw new RequiredOrganizationException();
418                    }
419    
420                    // Asset
421    
422                    assetEntryLocalService.deleteEntry(
423                            Organization.class.getName(), organization.getOrganizationId());
424    
425                    // Addresses
426    
427                    addressLocalService.deleteAddresses(
428                            organization.getCompanyId(), Organization.class.getName(),
429                            organization.getOrganizationId());
430    
431                    // Email addresses
432    
433                    emailAddressLocalService.deleteEmailAddresses(
434                            organization.getCompanyId(), Organization.class.getName(),
435                            organization.getOrganizationId());
436    
437                    // Expando
438    
439                    expandoRowLocalService.deleteRows(organization.getOrganizationId());
440    
441                    // Password policy relation
442    
443                    passwordPolicyRelLocalService.deletePasswordPolicyRel(
444                            Organization.class.getName(), organization.getOrganizationId());
445    
446                    // Phone
447    
448                    phoneLocalService.deletePhones(
449                            organization.getCompanyId(), Organization.class.getName(),
450                            organization.getOrganizationId());
451    
452                    // Website
453    
454                    websiteLocalService.deleteWebsites(
455                            organization.getCompanyId(), Organization.class.getName(),
456                            organization.getOrganizationId());
457    
458                    // Group
459    
460                    Group group = organization.getGroup();
461    
462                    if (group.isSite()) {
463                            group.setSite(false);
464    
465                            groupPersistence.update(group);
466                    }
467    
468                    groupLocalService.deleteGroup(group);
469    
470                    // Resources
471    
472                    String name = Organization.class.getName();
473    
474                    resourceLocalService.deleteResource(
475                            organization.getCompanyId(), name,
476                            ResourceConstants.SCOPE_INDIVIDUAL,
477                            organization.getOrganizationId());
478    
479                    // Organization
480    
481                    organizationPersistence.remove(organization);
482    
483                    // Permission cache
484    
485                    PermissionCacheUtil.clearCache();
486    
487                    return organization;
488            }
489    
490            /**
491             * Returns the organization with the name.
492             *
493             * @param  companyId the primary key of the organization's company
494             * @param  name the organization's name
495             * @return the organization with the name, or <code>null</code> if no
496             *         organization could be found
497             */
498            @Override
499            public Organization fetchOrganization(long companyId, String name) {
500                    return organizationPersistence.fetchByC_N(companyId, name);
501            }
502    
503            @Override
504            public List<Organization> getGroupUserOrganizations(
505                            long groupId, long userId)
506                    throws PortalException {
507    
508                    long[] groupOrganizationIds =
509                            groupPersistence.getOrganizationPrimaryKeys(groupId);
510    
511                    if (groupOrganizationIds.length == 0) {
512                            return Collections.emptyList();
513                    }
514    
515                    long[] userOrganizationIds = userPersistence.getOrganizationPrimaryKeys(
516                            userId);
517    
518                    if (userOrganizationIds.length == 0) {
519                            return Collections.emptyList();
520                    }
521    
522                    Set<Long> organizationIds = SetUtil.intersect(
523                            groupOrganizationIds, userOrganizationIds);
524    
525                    if (organizationIds.isEmpty()) {
526                            return Collections.emptyList();
527                    }
528    
529                    List<Organization> organizations = new ArrayList<>(
530                            organizationIds.size());
531    
532                    for (Long organizationId : organizationIds) {
533                            organizations.add(
534                                    organizationPersistence.findByPrimaryKey(organizationId));
535                    }
536    
537                    return organizations;
538            }
539    
540            @Override
541            public List<Organization> getNoAssetOrganizations() {
542                    return organizationFinder.findByNoAssets();
543            }
544    
545            /**
546             * Returns the organization with the name.
547             *
548             * @param  companyId the primary key of the organization's company
549             * @param  name the organization's name
550             * @return the organization with the name
551             * @throws PortalException if the organization with the name could not be
552             *         found
553             */
554            @Override
555            public Organization getOrganization(long companyId, String name)
556                    throws PortalException {
557    
558                    return organizationPersistence.findByC_N(companyId, name);
559            }
560    
561            /**
562             * Returns the primary key of the organization with the name.
563             *
564             * @param  companyId the primary key of the organization's company
565             * @param  name the organization's name
566             * @return the primary key of the organization with the name, or
567             *         <code>0</code> if the organization could not be found
568             */
569            @Override
570            public long getOrganizationId(long companyId, String name) {
571                    Organization organization = organizationPersistence.fetchByC_N(
572                            companyId, name);
573    
574                    if (organization != null) {
575                            return organization.getOrganizationId();
576                    }
577                    else {
578                            return 0;
579                    }
580            }
581    
582            @Override
583            public List<Organization> getOrganizations(
584                            long userId, int start, int end,
585                            OrderByComparator<Organization> obc)
586                    throws PortalException {
587    
588                    User user = userPersistence.findByPrimaryKey(userId);
589    
590                    List<Organization> organizations = ListUtil.copy(
591                            userPersistence.getOrganizations(userId));
592    
593                    Iterator<Organization> iterator = organizations.iterator();
594    
595                    while (iterator.hasNext()) {
596                            Organization organization = iterator.next();
597    
598                            if (organization.getCompanyId() != user.getCompanyId()) {
599                                    iterator.remove();
600                            }
601                    }
602    
603                    if (organizations.isEmpty()) {
604                            return organizations;
605                    }
606    
607                    if (obc == null) {
608                            obc = new OrganizationNameComparator(true);
609                    }
610    
611                    Collections.sort(organizations, obc);
612    
613                    return ListUtil.subList(organizations, start, end);
614            }
615    
616            /**
617             * Returns all the organizations belonging to the parent organization.
618             *
619             * @param  companyId the primary key of the organization's company
620             * @param  parentOrganizationId the primary key of the organization's parent
621             *         organization
622             * @return the organizations belonging to the parent organization
623             */
624            @Override
625            public List<Organization> getOrganizations(
626                    long companyId, long parentOrganizationId) {
627    
628                    return getOrganizations(
629                            companyId, parentOrganizationId, QueryUtil.ALL_POS,
630                            QueryUtil.ALL_POS);
631            }
632    
633            /**
634             * Returns a range of all the organizations belonging to the parent
635             * organization.
636             *
637             * <p>
638             * Useful when paginating results. Returns a maximum of <code>end -
639             * start</code> instances. <code>start</code> and <code>end</code> are not
640             * primary keys, they are indexes in the result set. Thus, <code>0</code>
641             * refers to the first result in the set. Setting both <code>start</code>
642             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
643             * result set.
644             * </p>
645             *
646             * @param  companyId the primary key of the organization's company
647             * @param  parentOrganizationId the primary key of the organization's parent
648             *         organization
649             * @param  start the lower bound of the range of organizations to return
650             * @param  end the upper bound of the range of organizations to return (not
651             *         inclusive)
652             * @return the range of organizations belonging to the parent organization
653             * @see    com.liferay.portal.service.persistence.OrganizationPersistence#findByC_P(
654             *         long, long, int, int)
655             */
656            @Override
657            public List<Organization> getOrganizations(
658                    long companyId, long parentOrganizationId, int start, int end) {
659    
660                    if (parentOrganizationId ==
661                                    OrganizationConstants.ANY_PARENT_ORGANIZATION_ID) {
662    
663                            return organizationPersistence.findByCompanyId(
664                                    companyId, start, end);
665                    }
666                    else {
667                            return organizationPersistence.findByC_P(
668                                    companyId, parentOrganizationId, start, end);
669                    }
670            }
671    
672            /**
673             * Returns the organizations with the primary keys.
674             *
675             * @param  organizationIds the primary keys of the organizations
676             * @return the organizations with the primary keys
677             * @throws PortalException if any one of the organizations could not be
678             *         found
679             */
680            @Override
681            public List<Organization> getOrganizations(long[] organizationIds)
682                    throws PortalException {
683    
684                    List<Organization> organizations = new ArrayList<>(
685                            organizationIds.length);
686    
687                    for (long organizationId : organizationIds) {
688                            Organization organization = getOrganization(organizationId);
689    
690                            organizations.add(organization);
691                    }
692    
693                    return organizations;
694            }
695    
696            /**
697             * Returns the number of organizations belonging to the parent organization.
698             *
699             * @param  companyId the primary key of the organization's company
700             * @param  parentOrganizationId the primary key of the organization's parent
701             *         organization
702             * @return the number of organizations belonging to the parent organization
703             */
704            @Override
705            public int getOrganizationsCount(
706                    long companyId, long parentOrganizationId) {
707    
708                    if (parentOrganizationId ==
709                                    OrganizationConstants.ANY_PARENT_ORGANIZATION_ID) {
710    
711                            return organizationPersistence.countByCompanyId(companyId);
712                    }
713                    else {
714                            return organizationPersistence.countByC_P(
715                                    companyId, parentOrganizationId);
716                    }
717            }
718    
719            /**
720             * Returns the parent organizations in order by closest ancestor. The list
721             * starts with the organization itself.
722             *
723             * @param  organizationId the primary key of the organization
724             * @return the parent organizations in order by closest ancestor
725             * @throws PortalException if an organization with the primary key could not
726             *         be found
727             */
728            @Override
729            public List<Organization> getParentOrganizations(long organizationId)
730                    throws PortalException {
731    
732                    if (organizationId ==
733                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
734    
735                            return new ArrayList<>();
736                    }
737    
738                    Organization organization = organizationPersistence.findByPrimaryKey(
739                            organizationId);
740    
741                    return organization.getAncestors();
742            }
743    
744            /**
745             * Returns the suborganizations of the organizations.
746             *
747             * @param  organizations the organizations from which to get
748             *         suborganizations
749             * @return the suborganizations of the organizations
750             */
751            @Override
752            public List<Organization> getSuborganizations(
753                    List<Organization> organizations) {
754    
755                    List<Organization> allSuborganizations = new ArrayList<>();
756    
757                    for (int i = 0; i < organizations.size(); i++) {
758                            Organization organization = organizations.get(i);
759    
760                            List<Organization> suborganizations =
761                                    organizationPersistence.findByC_P(
762                                            organization.getCompanyId(),
763                                            organization.getOrganizationId());
764    
765                            addSuborganizations(allSuborganizations, suborganizations);
766                    }
767    
768                    return allSuborganizations;
769            }
770    
771            /**
772             * Returns the suborganizations of the organization.
773             *
774             * @param  companyId the primary key of the organization's company
775             * @param  organizationId the primary key of the organization
776             * @return the suborganizations of the organization
777             */
778            @Override
779            public List<Organization> getSuborganizations(
780                    long companyId, long organizationId) {
781    
782                    return organizationPersistence.findByC_P(companyId, organizationId);
783            }
784    
785            /**
786             * Returns the count of suborganizations of the organization.
787             *
788             * @param  companyId the primary key of the organization's company
789             * @param  organizationId the primary key of the organization
790             * @return the count of suborganizations of the organization
791             */
792            @Override
793            public int getSuborganizationsCount(long companyId, long organizationId) {
794                    return organizationPersistence.countByC_P(companyId, organizationId);
795            }
796    
797            /**
798             * Returns the intersection of <code>allOrganizations</code> and
799             * <code>availableOrganizations</code>.
800             *
801             * @param  allOrganizations the organizations to check for availability
802             * @param  availableOrganizations the available organizations
803             * @return the intersection of <code>allOrganizations</code> and
804             *         <code>availableOrganizations</code>
805             */
806            @Override
807            public List<Organization> getSubsetOrganizations(
808                    List<Organization> allOrganizations,
809                    List<Organization> availableOrganizations) {
810    
811                    List<Organization> subsetOrganizations = new ArrayList<>();
812    
813                    for (Organization organization : allOrganizations) {
814                            if (availableOrganizations.contains(organization)) {
815                                    subsetOrganizations.add(organization);
816                            }
817                    }
818    
819                    return subsetOrganizations;
820            }
821    
822            /**
823             * Returns all the IDs of organizations with which the user is explicitly
824             * associated, optionally including the IDs of organizations that the user
825             * administers or owns.
826             *
827             * <p>
828             * A user is considered to be <i>explicitly</i> associated with an
829             * organization if his account is individually created within the
830             * organization or if the user is later added to it.
831             * </p>
832             *
833             * @param  userId the primary key of the user
834             * @param  includeAdministrative whether to include the IDs of organizations
835             *         that the user administers or owns, even if he's not a member of
836             *         the organizations
837             * @return the IDs of organizations with which the user is explicitly
838             *         associated, optionally including the IDs of organizations that
839             *         the user administers or owns
840             * @throws PortalException if a user with the primary key could not be found
841             *         or if a portal exception occurred
842             */
843            @Override
844            public long[] getUserOrganizationIds(
845                            long userId, boolean includeAdministrative)
846                    throws PortalException {
847    
848                    if (!includeAdministrative) {
849                            return userPersistence.getOrganizationPrimaryKeys(userId);
850                    }
851    
852                    Set<Long> organizationIds = SetUtil.fromArray(
853                            userPersistence.getOrganizationPrimaryKeys(userId));
854    
855                    List<UserGroupRole> userGroupRoles =
856                            userGroupRoleLocalService.getUserGroupRoles(userId);
857    
858                    for (UserGroupRole userGroupRole : userGroupRoles) {
859                            Role role = userGroupRole.getRole();
860    
861                            String roleName = role.getName();
862    
863                            if (roleName.equals(RoleConstants.ORGANIZATION_ADMINISTRATOR) ||
864                                    roleName.equals(RoleConstants.ORGANIZATION_OWNER)) {
865    
866                                    Group group = userGroupRole.getGroup();
867    
868                                    organizationIds.add(group.getOrganizationId());
869                            }
870                    }
871    
872                    return ArrayUtil.toLongArray(organizationIds);
873            }
874    
875            /**
876             * Returns all the organizations with which the user is explicitly
877             * associated, optionally including the organizations that the user
878             * administers or owns.
879             *
880             * <p>
881             * A user is considered to be <i>explicitly</i> associated with an
882             * organization if his account is individually created within the
883             * organization or if the user is later added as a member.
884             * </p>
885             *
886             * @param  userId the primary key of the user
887             * @param  includeAdministrative whether to include the IDs of organizations
888             *         that the user administers or owns, even if he's not a member of
889             *         the organizations
890             * @return the organizations with which the user is explicitly associated,
891             *         optionally including the organizations that the user administers
892             *         or owns
893             * @throws PortalException if a user with the primary key could not be found
894             */
895            @Override
896            public List<Organization> getUserOrganizations(
897                            long userId, boolean includeAdministrative)
898                    throws PortalException {
899    
900                    if (!includeAdministrative) {
901                            return getUserOrganizations(userId);
902                    }
903    
904                    Set<Organization> organizations = new HashSet<>(
905                            getUserOrganizations(userId));
906    
907                    List<UserGroupRole> userGroupRoles =
908                            userGroupRoleLocalService.getUserGroupRoles(userId);
909    
910                    for (UserGroupRole userGroupRole : userGroupRoles) {
911                            Role role = userGroupRole.getRole();
912    
913                            String roleName = role.getName();
914    
915                            if (roleName.equals(RoleConstants.ORGANIZATION_ADMINISTRATOR) ||
916                                    roleName.equals(RoleConstants.ORGANIZATION_OWNER)) {
917    
918                                    Group group = userGroupRole.getGroup();
919    
920                                    Organization organization =
921                                            organizationPersistence.findByPrimaryKey(
922                                                    group.getOrganizationId());
923    
924                                    organizations.add(organization);
925                            }
926                    }
927    
928                    return new ArrayList<>(organizations);
929            }
930    
931            /**
932             * Returns <code>true</code> if the password policy has been assigned to the
933             * organization.
934             *
935             * @param  passwordPolicyId the primary key of the password policy
936             * @param  organizationId the primary key of the organization
937             * @return <code>true</code> if the password policy has been assigned to the
938             *         organization; <code>false</code> otherwise
939             */
940            @Override
941            public boolean hasPasswordPolicyOrganization(
942                    long passwordPolicyId, long organizationId) {
943    
944                    return passwordPolicyRelLocalService.hasPasswordPolicyRel(
945                            passwordPolicyId, Organization.class.getName(), organizationId);
946            }
947    
948            /**
949             * Returns <code>true</code> if the user is a member of the organization,
950             * optionally focusing on suborganizations or the specified organization.
951             * This method is usually called to determine if the user has view access to
952             * a resource belonging to the organization.
953             *
954             * <ol>
955             * <li>
956             * If <code>inheritSuborganizations=<code>false</code></code>:
957             * the method checks whether the user belongs to the organization specified
958             * by <code>organizationId</code>. The parameter
959             * <code>includeSpecifiedOrganization</code> is ignored.
960             * </li>
961             * <li>
962             * The parameter <code>includeSpecifiedOrganization</code> is
963             * ignored unless <code>inheritSuborganizations</code> is also
964             * <code>true</code>.
965             * </li>
966             * <li>
967             * If <code>inheritSuborganizations=<code>true</code></code> and
968             * <code>includeSpecifiedOrganization=<code>false</code></code>: the method
969             * checks
970             * whether the user belongs to one of the child organizations of the one
971             * specified by <code>organizationId</code>.
972             * </li>
973             * <li>
974             * If <code>inheritSuborganizations=<code>true</code></code> and
975             * <code>includeSpecifiedOrganization=<code>true</code></code>: the method
976             * checks whether
977             * the user belongs to the organization specified by
978             * <code>organizationId</code> or any of
979             * its child organizations.
980             * </li>
981             * </ol>
982             *
983             * @param  userId the primary key of the organization's user
984             * @param  organizationId the primary key of the organization
985             * @param  inheritSuborganizations if <code>true</code> suborganizations are
986             *         considered in the determination
987             * @param  includeSpecifiedOrganization if <code>true</code> the
988             *         organization specified by <code>organizationId</code> is
989             *         considered in the determination
990             * @return <code>true</code> if the user has access to the organization;
991             *         <code>false</code> otherwise
992             * @throws PortalException if an organization with the primary key could not
993             *         be found
994             * @see    com.liferay.portal.service.persistence.OrganizationFinder
995             */
996            @Override
997            public boolean hasUserOrganization(
998                            long userId, long organizationId, boolean inheritSuborganizations,
999                            boolean includeSpecifiedOrganization)
1000                    throws PortalException {
1001    
1002                    if (!inheritSuborganizations) {
1003                            return userPersistence.containsOrganization(userId, organizationId);
1004                    }
1005    
1006                    LinkedHashMap<String, Object> params = new LinkedHashMap<>();
1007    
1008                    List<Organization> organizationsTree = new ArrayList<>();
1009    
1010                    Organization organization = organizationPersistence.findByPrimaryKey(
1011                            organizationId);
1012    
1013                    if (!includeSpecifiedOrganization) {
1014                            organizationsTree.add(organization);
1015                    }
1016                    else {
1017                            organizationsTree.add(organization.getParentOrganization());
1018                    }
1019    
1020                    params.put("usersOrgsTree", organizationsTree);
1021    
1022                    if (userFinder.countByUser(userId, params) > 0) {
1023                            return true;
1024                    }
1025    
1026                    return false;
1027            }
1028    
1029            /**
1030             * Rebuilds the organization's tree.
1031             *
1032             * <p>
1033             * Only call this method if the tree has become stale through operations
1034             * other than normal CRUD. Under normal circumstances the tree is
1035             * automatically rebuilt whenever necessary.
1036             * </p>
1037             *
1038             * @param  companyId the primary key of the organization's company
1039             * @throws PortalException if an organization with the primary key could not
1040             *         be found
1041             */
1042            @Override
1043            public void rebuildTree(long companyId) throws PortalException {
1044                    TreePathUtil.rebuildTree(
1045                            companyId, OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID,
1046                            StringPool.SLASH,
1047                            new TreeModelTasksAdapter<Organization>() {
1048    
1049                                    @Override
1050                                    public List<Organization> findTreeModels(
1051                                            long previousId, long companyId, long parentPrimaryKey,
1052                                            int size) {
1053    
1054                                            return organizationPersistence.findByO_C_P(
1055                                                    previousId, companyId, parentPrimaryKey,
1056                                                    QueryUtil.ALL_POS, size,
1057                                                    new OrganizationIdComparator(true));
1058                                    }
1059    
1060                            }
1061                    );
1062            }
1063    
1064            /**
1065             * Returns an ordered range of all the organizations that match the
1066             * keywords, using the indexer. It is preferable to use this method instead
1067             * of the non-indexed version whenever possible for performance reasons.
1068             *
1069             * <p>
1070             * Useful when paginating results. Returns a maximum of <code>end -
1071             * start</code> instances. <code>start</code> and <code>end</code> are not
1072             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1073             * refers to the first result in the set. Setting both <code>start</code>
1074             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
1075             * result set.
1076             * </p>
1077             *
1078             * @param  companyId the primary key of the organization's company
1079             * @param  parentOrganizationId the primary key of the organization's parent
1080             *         organization
1081             * @param  keywords the keywords (space separated), which may occur in the
1082             *         organization's name, street, city, zipcode, type, region or
1083             *         country (optionally <code>null</code>)
1084             * @param  params the finder parameters (optionally <code>null</code>). For
1085             *         more information see {@link
1086             *         com.liferay.portlet.usersadmin.util.OrganizationIndexer}
1087             * @param  start the lower bound of the range of organizations to return
1088             * @param  end the upper bound of the range of organizations to return (not
1089             *         inclusive)
1090             * @param  sort the field and direction by which to sort (optionally
1091             *         <code>null</code>)
1092             * @return the matching organizations ordered by name
1093             * @see    com.liferay.portlet.usersadmin.util.OrganizationIndexer
1094             */
1095            @Override
1096            public Hits search(
1097                    long companyId, long parentOrganizationId, String keywords,
1098                    LinkedHashMap<String, Object> params, int start, int end, Sort sort) {
1099    
1100                    String name = null;
1101                    String type = null;
1102                    String street = null;
1103                    String city = null;
1104                    String zip = null;
1105                    String region = null;
1106                    String country = null;
1107                    boolean andOperator = false;
1108    
1109                    if (Validator.isNotNull(keywords)) {
1110                            name = keywords;
1111                            type = keywords;
1112                            street = keywords;
1113                            city = keywords;
1114                            zip = keywords;
1115                            region = keywords;
1116                            country = keywords;
1117                    }
1118                    else {
1119                            andOperator = true;
1120                    }
1121    
1122                    if (params != null) {
1123                            params.put("keywords", keywords);
1124                    }
1125    
1126                    return search(
1127                            companyId, parentOrganizationId, name, type, street, city, zip,
1128                            region, country, params, andOperator, start, end, sort);
1129            }
1130    
1131            /**
1132             * Returns a name ordered range of all the organizations that match the
1133             * keywords, type, region, and country, without using the indexer. It is
1134             * preferable to use the indexed version {@link #search(long, long, String,
1135             * LinkedHashMap, int, int, Sort)} instead of this method wherever possible
1136             * for performance reasons.
1137             *
1138             * <p>
1139             * Useful when paginating results. Returns a maximum of <code>end -
1140             * start</code> instances. <code>start</code> and <code>end</code> are not
1141             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1142             * refers to the first result in the set. Setting both <code>start</code>
1143             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
1144             * result set.
1145             * </p>
1146             *
1147             * @param  companyId the primary key of the organization's company
1148             * @param  parentOrganizationId the primary key of the organization's parent
1149             *         organization
1150             * @param  keywords the keywords (space separated), which may occur in the
1151             *         organization's name, street, city, or zipcode (optionally
1152             *         <code>null</code>)
1153             * @param  type the organization's type (optionally <code>null</code>)
1154             * @param  regionId the primary key of the organization's region (optionally
1155             *         <code>null</code>)
1156             * @param  countryId the primary key of the organization's country
1157             *         (optionally <code>null</code>)
1158             * @param  params the finder params. For more information see {@link
1159             *         com.liferay.portal.service.persistence.OrganizationFinder}
1160             * @param  start the lower bound of the range of organizations to return
1161             * @param  end the upper bound of the range of organizations to return (not
1162             *         inclusive)
1163             * @return the matching organizations ordered by name
1164             * @see    com.liferay.portal.service.persistence.OrganizationFinder
1165             */
1166            @Override
1167            public List<Organization> search(
1168                    long companyId, long parentOrganizationId, String keywords, String type,
1169                    Long regionId, Long countryId, LinkedHashMap<String, Object> params,
1170                    int start, int end) {
1171    
1172                    return search(
1173                            companyId, parentOrganizationId, keywords, type, regionId,
1174                            countryId, params, start, end,
1175                            new OrganizationNameComparator(true));
1176            }
1177    
1178            /**
1179             * Returns an ordered range of all the organizations that match the
1180             * keywords, type, region, and country, without using the indexer. It is
1181             * preferable to use the indexed version {@link #search(long, long, String,
1182             * String, String, String, String, String, String, LinkedHashMap, boolean,
1183             * int, int, Sort)} instead of this method wherever possible for performance
1184             * reasons.
1185             *
1186             * <p>
1187             * Useful when paginating results. Returns a maximum of <code>end -
1188             * start</code> instances. <code>start</code> and <code>end</code> are not
1189             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1190             * refers to the first result in the set. Setting both <code>start</code>
1191             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
1192             * result set.
1193             * </p>
1194             *
1195             * @param  companyId the primary key of the organization's company
1196             * @param  parentOrganizationId the primary key of the organization's parent
1197             *         organization
1198             * @param  keywords the keywords (space separated), which may occur in the
1199             *         organization's name, street, city, or zipcode (optionally
1200             *         <code>null</code>)
1201             * @param  type the organization's type (optionally <code>null</code>)
1202             * @param  regionId the primary key of the organization's region (optionally
1203             *         <code>null</code>)
1204             * @param  countryId the primary key of the organization's country
1205             *         (optionally <code>null</code>)
1206             * @param  params the finder params. For more information see {@link
1207             *         com.liferay.portal.service.persistence.OrganizationFinder}
1208             * @param  start the lower bound of the range of organizations to return
1209             * @param  end the upper bound of the range of organizations to return (not
1210             *         inclusive)
1211             * @param  obc the comparator to order the organizations (optionally
1212             *         <code>null</code>)
1213             * @return the matching organizations ordered by comparator <code>obc</code>
1214             * @see    com.liferay.portal.service.persistence.OrganizationFinder
1215             */
1216            @Override
1217            public List<Organization> search(
1218                    long companyId, long parentOrganizationId, String keywords, String type,
1219                    Long regionId, Long countryId, LinkedHashMap<String, Object> params,
1220                    int start, int end, OrderByComparator<Organization> obc) {
1221    
1222                    String parentOrganizationIdComparator = StringPool.EQUAL;
1223    
1224                    if (parentOrganizationId ==
1225                                    OrganizationConstants.ANY_PARENT_ORGANIZATION_ID) {
1226    
1227                            parentOrganizationIdComparator = StringPool.NOT_EQUAL;
1228                    }
1229    
1230                    return organizationFinder.findByKeywords(
1231                            companyId, parentOrganizationId, parentOrganizationIdComparator,
1232                            keywords, type, regionId, countryId, params, start, end, obc);
1233            }
1234    
1235            /**
1236             * Returns a name ordered range of all the organizations with the type,
1237             * region, and country, and whose name, street, city, and zipcode match the
1238             * keywords specified for them, without using the indexer. It is preferable
1239             * to use the indexed version {@link #search(long, long, String, String,
1240             * String, String, String, String, String, LinkedHashMap, boolean, int, int,
1241             * Sort)} instead of this method wherever possible for performance reasons.
1242             *
1243             * <p>
1244             * Useful when paginating results. Returns a maximum of <code>end -
1245             * start</code> instances. <code>start</code> and <code>end</code> are not
1246             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1247             * refers to the first result in the set. Setting both <code>start</code>
1248             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
1249             * result set.
1250             * </p>
1251             *
1252             * @param  companyId the primary key of the organization's company
1253             * @param  parentOrganizationId the primary key of the organization's parent
1254             * @param  name the name keywords (space separated, optionally
1255             *         <code>null</code>)
1256             * @param  type the organization's type (optionally <code>null</code>)
1257             * @param  street the street keywords (optionally <code>null</code>)
1258             * @param  city the city keywords (optionally <code>null</code>)
1259             * @param  zip the zipcode keywords (optionally <code>null</code>)
1260             * @param  regionId the primary key of the organization's region (optionally
1261             *         <code>null</code>)
1262             * @param  countryId the primary key of the organization's country
1263             *         (optionally <code>null</code>)
1264             * @param  params the finder parameters (optionally <code>null</code>). For
1265             *         more information see {@link
1266             *         com.liferay.portal.service.persistence.OrganizationFinder}
1267             * @param  andOperator whether every field must match its keywords, or just
1268             *         one field. For example, &quot;organizations with the name
1269             *         'Employees' and city 'Chicago'&quot; vs &quot;organizations with
1270             *         the name 'Employees' or the city 'Chicago'&quot;.
1271             * @param  start the lower bound of the range of organizations to return
1272             * @param  end the upper bound of the range of organizations to return (not
1273             *         inclusive)
1274             * @return the matching organizations ordered by name
1275             * @see    com.liferay.portal.service.persistence.OrganizationFinder
1276             */
1277            @Override
1278            public List<Organization> search(
1279                    long companyId, long parentOrganizationId, String name, String type,
1280                    String street, String city, String zip, Long regionId, Long countryId,
1281                    LinkedHashMap<String, Object> params, boolean andOperator, int start,
1282                    int end) {
1283    
1284                    return search(
1285                            companyId, parentOrganizationId, name, type, street, city, zip,
1286                            regionId, countryId, params, andOperator, start, end,
1287                            new OrganizationNameComparator(true));
1288            }
1289    
1290            /**
1291             * Returns an ordered range of all the organizations with the type, region,
1292             * and country, and whose name, street, city, and zipcode match the keywords
1293             * specified for them, without using the indexer. It is preferable to use
1294             * the indexed version {@link #search(long, long, String, String, String,
1295             * String, String, String, String, LinkedHashMap, boolean, int, int, Sort)}
1296             * instead of this method wherever possible for performance reasons.
1297             *
1298             * <p>
1299             * Useful when paginating results. Returns a maximum of <code>end -
1300             * start</code> instances. <code>start</code> and <code>end</code> are not
1301             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1302             * refers to the first result in the set. Setting both <code>start</code>
1303             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
1304             * result set.
1305             * </p>
1306             *
1307             * @param  companyId the primary key of the organization's company
1308             * @param  parentOrganizationId the primary key of the organization's parent
1309             *         organization
1310             * @param  name the name keywords (space separated, optionally
1311             *         <code>null</code>)
1312             * @param  type the organization's type (optionally <code>null</code>)
1313             * @param  street the street keywords (optionally <code>null</code>)
1314             * @param  city the city keywords (optionally <code>null</code>)
1315             * @param  zip the zipcode keywords (optionally <code>null</code>)
1316             * @param  regionId the primary key of the organization's region (optionally
1317             *         <code>null</code>)
1318             * @param  countryId the primary key of the organization's country
1319             *         (optionally <code>null</code>)
1320             * @param  params the finder parameters (optionally <code>null</code>). For
1321             *         more information see {@link
1322             *         com.liferay.portal.service.persistence.OrganizationFinder}
1323             * @param  andOperator whether every field must match its keywords, or just
1324             *         one field. For example, &quot;organizations with the name
1325             *         'Employees' and city 'Chicago'&quot; vs &quot;organizations with
1326             *         the name 'Employees' or the city 'Chicago'&quot;.
1327             * @param  start the lower bound of the range of organizations to return
1328             * @param  end the upper bound of the range of organizations to return (not
1329             *         inclusive)
1330             * @param  obc the comparator to order the organizations (optionally
1331             *         <code>null</code>)
1332             * @return the matching organizations ordered by comparator <code>obc</code>
1333             * @see    com.liferay.portal.service.persistence.OrganizationFinder
1334             */
1335            @Override
1336            public List<Organization> search(
1337                    long companyId, long parentOrganizationId, String name, String type,
1338                    String street, String city, String zip, Long regionId, Long countryId,
1339                    LinkedHashMap<String, Object> params, boolean andOperator, int start,
1340                    int end, OrderByComparator<Organization> obc) {
1341    
1342                    String parentOrganizationIdComparator = StringPool.EQUAL;
1343    
1344                    if (parentOrganizationId ==
1345                                    OrganizationConstants.ANY_PARENT_ORGANIZATION_ID) {
1346    
1347                            parentOrganizationIdComparator = StringPool.NOT_EQUAL;
1348                    }
1349    
1350                    return organizationFinder.findByC_PO_N_T_S_C_Z_R_C(
1351                            companyId, parentOrganizationId, parentOrganizationIdComparator,
1352                            name, type, street, city, zip, regionId, countryId, params,
1353                            andOperator, start, end, obc);
1354            }
1355    
1356            /**
1357             * Returns an ordered range of all the organizations whose name, type, or
1358             * location fields match the keywords specified for them, using the indexer.
1359             * It is preferable to use this method instead of the non-indexed version
1360             * whenever possible for performance reasons.
1361             *
1362             * <p>
1363             * Useful when paginating results. Returns a maximum of <code>end -
1364             * start</code> instances. <code>start</code> and <code>end</code> are not
1365             * primary keys, they are indexes in the result set. Thus, <code>0</code>
1366             * refers to the first result in the set. Setting both <code>start</code>
1367             * and <code>end</code> to {@link QueryUtil#ALL_POS} will return the full
1368             * result set.
1369             * </p>
1370             *
1371             * @param  companyId the primary key of the organization's company
1372             * @param  parentOrganizationId the primary key of the organization's parent
1373             *         organization
1374             * @param  name the name keywords (space separated, optionally
1375             *         <code>null</code>)
1376             * @param  type the type keywords (optionally <code>null</code>)
1377             * @param  street the street keywords (optionally <code>null</code>)
1378             * @param  city the city keywords (optionally <code>null</code>)
1379             * @param  zip the zipcode keywords (optionally <code>null</code>)
1380             * @param  region the region keywords (optionally <code>null</code>)
1381             * @param  country the country keywords (optionally <code>null</code>)
1382             * @param  params the finder parameters (optionally <code>null</code>). For
1383             *         more information see {@link
1384             *         com.liferay.portlet.usersadmin.util.OrganizationIndexer}.
1385             * @param  andSearch whether every field must match its keywords or just one
1386             *         field
1387             * @param  start the lower bound of the range of organizations to return
1388             * @param  end the upper bound of the range of organizations to return (not
1389             *         inclusive)
1390             * @param  sort the field and direction by which to sort (optionally
1391             *         <code>null</code>)
1392             * @return the matching organizations ordered by <code>sort</code>
1393             * @see    com.liferay.portlet.usersadmin.util.OrganizationIndexer
1394             */
1395            @Override
1396            public Hits search(
1397                    long companyId, long parentOrganizationId, String name, String type,
1398                    String street, String city, String zip, String region, String country,
1399                    LinkedHashMap<String, Object> params, boolean andSearch, int start,
1400                    int end, Sort sort) {
1401    
1402                    try {
1403                            Indexer<Organization> indexer =
1404                                    IndexerRegistryUtil.nullSafeGetIndexer(Organization.class);
1405    
1406                            SearchContext searchContext = buildSearchContext(
1407                                    companyId, parentOrganizationId, name, type, street, city, zip,
1408                                    region, country, params, andSearch, start, end, sort);
1409    
1410                            return indexer.search(searchContext);
1411                    }
1412                    catch (Exception e) {
1413                            throw new SystemException(e);
1414                    }
1415            }
1416    
1417            /**
1418             * Returns the number of organizations that match the keywords, type,
1419             * region, and country.
1420             *
1421             * @param  companyId the primary key of the organization's company
1422             * @param  parentOrganizationId the primary key of the organization's parent
1423             *         organization
1424             * @param  keywords the keywords (space separated), which may occur in the
1425             *         organization's name, street, city, or zipcode (optionally
1426             *         <code>null</code>)
1427             * @param  type the organization's type (optionally <code>null</code>)
1428             * @param  regionId the primary key of the organization's region (optionally
1429             *         <code>null</code>)
1430             * @param  countryId the primary key of the organization's country
1431             *         (optionally <code>null</code>)
1432             * @param  params the finder parameters (optionally <code>null</code>). For
1433             *         more information see {@link
1434             *         com.liferay.portal.service.persistence.OrganizationFinder}
1435             * @return the number of matching organizations
1436             * @see    com.liferay.portal.service.persistence.OrganizationFinder
1437             */
1438            @Override
1439            public int searchCount(
1440                    long companyId, long parentOrganizationId, String keywords, String type,
1441                    Long regionId, Long countryId, LinkedHashMap<String, Object> params) {
1442    
1443                    Indexer<?> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1444                            Organization.class);
1445    
1446                    if (!indexer.isIndexerEnabled() ||
1447                            !PropsValues.ORGANIZATIONS_SEARCH_WITH_INDEX ||
1448                            isUseCustomSQL(params)) {
1449    
1450                            String parentOrganizationIdComparator = StringPool.EQUAL;
1451    
1452                            if (parentOrganizationId ==
1453                                            OrganizationConstants.ANY_PARENT_ORGANIZATION_ID) {
1454    
1455                                    parentOrganizationIdComparator = StringPool.NOT_EQUAL;
1456                            }
1457    
1458                            return organizationFinder.countByKeywords(
1459                                    companyId, parentOrganizationId, parentOrganizationIdComparator,
1460                                    keywords, type, regionId, countryId, params);
1461                    }
1462    
1463                    try {
1464                            String name = null;
1465                            String street = null;
1466                            String city = null;
1467                            String zip = null;
1468                            boolean andOperator = false;
1469    
1470                            if (Validator.isNotNull(keywords)) {
1471                                    name = keywords;
1472                                    street = keywords;
1473                                    city = keywords;
1474                                    zip = keywords;
1475                            }
1476                            else {
1477                                    andOperator = true;
1478                            }
1479    
1480                            if (params != null) {
1481                                    params.put("keywords", keywords);
1482                            }
1483    
1484                            SearchContext searchContext = buildSearchContext(
1485                                    companyId, parentOrganizationId, name, type, street, city, zip,
1486                                    regionId, countryId, params, andOperator, QueryUtil.ALL_POS,
1487                                    QueryUtil.ALL_POS, null);
1488    
1489                            return (int)indexer.searchCount(searchContext);
1490                    }
1491                    catch (Exception e) {
1492                            throw new SystemException(e);
1493                    }
1494            }
1495    
1496            /**
1497             * Returns the number of organizations with the type, region, and country,
1498             * and whose name, street, city, and zipcode match the keywords specified
1499             * for them.
1500             *
1501             * @param  companyId the primary key of the organization's company
1502             * @param  parentOrganizationId the primary key of the organization's parent
1503             *         organization
1504             * @param  name the name keywords (space separated, optionally
1505             *         <code>null</code>)
1506             * @param  type the organization's type (optionally <code>null</code>)
1507             * @param  street the street keywords (optionally <code>null</code>)
1508             * @param  city the city keywords (optionally <code>null</code>)
1509             * @param  zip the zipcode keywords (optionally <code>null</code>)
1510             * @param  regionId the primary key of the organization's region (optionally
1511             *         <code>null</code>)
1512             * @param  countryId the primary key of the organization's country
1513             *         (optionally <code>null</code>)
1514             * @param  params the finder parameters (optionally <code>null</code>). For
1515             *         more information see {@link
1516             *         com.liferay.portal.service.persistence.OrganizationFinder}
1517             * @param  andOperator whether every field must match its keywords, or just
1518             *         one field. For example, &quot;organizations with the name
1519             *         'Employees' and city 'Chicago'&quot; vs &quot;organizations with
1520             *         the name 'Employees' or the city 'Chicago'&quot;.
1521             * @return the number of matching organizations
1522             * @see    com.liferay.portal.service.persistence.OrganizationFinder
1523             */
1524            @Override
1525            public int searchCount(
1526                    long companyId, long parentOrganizationId, String name, String type,
1527                    String street, String city, String zip, Long regionId, Long countryId,
1528                    LinkedHashMap<String, Object> params, boolean andOperator) {
1529    
1530                    Indexer<?> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1531                            Organization.class);
1532    
1533                    if (!indexer.isIndexerEnabled() ||
1534                            !PropsValues.ORGANIZATIONS_SEARCH_WITH_INDEX ||
1535                            isUseCustomSQL(params)) {
1536    
1537                            String parentOrganizationIdComparator = StringPool.EQUAL;
1538    
1539                            if (parentOrganizationId ==
1540                                            OrganizationConstants.ANY_PARENT_ORGANIZATION_ID) {
1541    
1542                                    parentOrganizationIdComparator = StringPool.NOT_EQUAL;
1543                            }
1544    
1545                            return organizationFinder.countByC_PO_N_T_S_C_Z_R_C(
1546                                    companyId, parentOrganizationId, parentOrganizationIdComparator,
1547                                    name, type, street, city, zip, regionId, countryId, params,
1548                                    andOperator);
1549                    }
1550    
1551                    try {
1552                            SearchContext searchContext = buildSearchContext(
1553                                    companyId, parentOrganizationId, name, type, street, city, zip,
1554                                    regionId, countryId, params, andOperator, QueryUtil.ALL_POS,
1555                                    QueryUtil.ALL_POS, null);
1556    
1557                            return (int)indexer.searchCount(searchContext);
1558                    }
1559                    catch (Exception e) {
1560                            throw new SystemException(e);
1561                    }
1562            }
1563    
1564            @Override
1565            public BaseModelSearchResult<Organization> searchOrganizations(
1566                            long companyId, long parentOrganizationId, String keywords,
1567                            LinkedHashMap<String, Object> params, int start, int end, Sort sort)
1568                    throws PortalException {
1569    
1570                    String name = null;
1571                    String type = null;
1572                    String street = null;
1573                    String city = null;
1574                    String zip = null;
1575                    String region = null;
1576                    String country = null;
1577                    boolean andOperator = false;
1578    
1579                    if (Validator.isNotNull(keywords)) {
1580                            name = keywords;
1581                            type = keywords;
1582                            street = keywords;
1583                            city = keywords;
1584                            zip = keywords;
1585                            region = keywords;
1586                            country = keywords;
1587                    }
1588                    else {
1589                            andOperator = true;
1590                    }
1591    
1592                    if (params != null) {
1593                            params.put("keywords", keywords);
1594                    }
1595    
1596                    return searchOrganizations(
1597                            companyId, parentOrganizationId, name, type, street, city, zip,
1598                            region, country, params, andOperator, start, end, sort);
1599            }
1600    
1601            @Override
1602            public BaseModelSearchResult<Organization> searchOrganizations(
1603                            long companyId, long parentOrganizationId, String name, String type,
1604                            String street, String city, String zip, String region,
1605                            String country, LinkedHashMap<String, Object> params,
1606                            boolean andSearch, int start, int end, Sort sort)
1607                    throws PortalException {
1608    
1609                    Indexer<Organization> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1610                            Organization.class);
1611    
1612                    SearchContext searchContext = buildSearchContext(
1613                            companyId, parentOrganizationId, name, type, street, city, zip,
1614                            region, country, params, andSearch, start, end, sort);
1615    
1616                    for (int i = 0; i < 10; i++) {
1617                            Hits hits = indexer.search(searchContext);
1618    
1619                            List<Organization> organizations = UsersAdminUtil.getOrganizations(
1620                                    hits);
1621    
1622                            if (organizations != null) {
1623                                    return new BaseModelSearchResult<>(
1624                                            organizations, hits.getLength());
1625                            }
1626                    }
1627    
1628                    throw new SearchException(
1629                            "Unable to fix the search index after 10 attempts");
1630            }
1631    
1632            /**
1633             * Sets the organizations in the group, removing and adding organizations to
1634             * the group as necessary.
1635             *
1636             * @param  groupId the primary key of the group
1637             * @param  organizationIds the primary keys of the organizations
1638             * @throws PortalException if a portal exception occurred
1639             */
1640            @Override
1641            public void setGroupOrganizations(long groupId, long[] organizationIds)
1642                    throws PortalException {
1643    
1644                    groupPersistence.setOrganizations(groupId, organizationIds);
1645    
1646                    PermissionCacheUtil.clearCache();
1647            }
1648    
1649            /**
1650             * Removes the organizations from the group.
1651             *
1652             * @param  groupId the primary key of the group
1653             * @param  organizationIds the primary keys of the organizations
1654             * @throws PortalException if a portal exception occurred
1655             */
1656            @Override
1657            public void unsetGroupOrganizations(long groupId, long[] organizationIds)
1658                    throws PortalException {
1659    
1660                    groupPersistence.removeOrganizations(groupId, organizationIds);
1661    
1662                    PermissionCacheUtil.clearCache();
1663            }
1664    
1665            /**
1666             * Removes the organizations from the password policy.
1667             *
1668             * @param passwordPolicyId the primary key of the password policy
1669             * @param organizationIds the primary keys of the organizations
1670             */
1671            @Override
1672            public void unsetPasswordPolicyOrganizations(
1673                    long passwordPolicyId, long[] organizationIds) {
1674    
1675                    passwordPolicyRelLocalService.deletePasswordPolicyRels(
1676                            passwordPolicyId, Organization.class.getName(), organizationIds);
1677            }
1678    
1679            /**
1680             * Updates the organization's asset with the new asset categories and tag
1681             * names, removing and adding asset categories and tag names as necessary.
1682             *
1683             * @param  userId the primary key of the user
1684             * @param  organization the organization
1685             * @param  assetCategoryIds the primary keys of the asset categories
1686             * @param  assetTagNames the asset tag names
1687             * @throws PortalException if a user with the primary key could not be found
1688             */
1689            @Override
1690            public void updateAsset(
1691                            long userId, Organization organization, long[] assetCategoryIds,
1692                            String[] assetTagNames)
1693                    throws PortalException {
1694    
1695                    User user = userPersistence.findByPrimaryKey(userId);
1696    
1697                    Company company = companyPersistence.findByPrimaryKey(
1698                            user.getCompanyId());
1699    
1700                    Group companyGroup = company.getGroup();
1701    
1702                    assetEntryLocalService.updateEntry(
1703                            userId, companyGroup.getGroupId(), null, null,
1704                            Organization.class.getName(), organization.getOrganizationId(),
1705                            organization.getUuid(), 0, assetCategoryIds, assetTagNames, false,
1706                            null, null, null, null, organization.getName(), StringPool.BLANK,
1707                            null, null, null, 0, 0, null);
1708            }
1709    
1710            /**
1711             * Updates the organization.
1712             *
1713             * @param      companyId the primary key of the organization's company
1714             * @param      organizationId the primary key of the organization
1715             * @param      parentOrganizationId the primary key of organization's parent
1716             *             organization
1717             * @param      name the organization's name
1718             * @param      type the organization's type
1719             * @param      recursable whether permissions of the organization are to be
1720             *             inherited by its suborganizations
1721             * @param      regionId the primary key of the organization's region
1722             * @param      countryId the primary key of the organization's country
1723             * @param      statusId the organization's workflow status
1724             * @param      comments the comments about the organization
1725             * @param      site whether the organization is to be associated with a main
1726             *             site
1727             * @param      serviceContext the service context to be applied (optionally
1728             *             <code>null</code>). Can set asset category IDs and asset tag
1729             *             names for the organization, and merge expando bridge
1730             *             attributes for the organization.
1731             * @return     the organization
1732             * @throws     PortalException if an organization or parent organization
1733             *             with the primary key could not be found or if the new
1734             *             information was invalid
1735             * @deprecated As of 6.2.0, replaced by {@link #updateOrganization(long,
1736             *             long, long, String, String, long, long, int, String, boolean,
1737             *             byte[], boolean, ServiceContext)}
1738             */
1739            @Deprecated
1740            @Override
1741            public Organization updateOrganization(
1742                            long companyId, long organizationId, long parentOrganizationId,
1743                            String name, String type, boolean recursable, long regionId,
1744                            long countryId, long statusId, String comments, boolean site,
1745                            ServiceContext serviceContext)
1746                    throws PortalException {
1747    
1748                    return updateOrganization(
1749                            companyId, organizationId, parentOrganizationId, name, type,
1750                            regionId, countryId, statusId, comments, true, null, site,
1751                            serviceContext);
1752            }
1753    
1754            /**
1755             * Updates the organization.
1756             *
1757             * @param  companyId the primary key of the organization's company
1758             * @param  organizationId the primary key of the organization
1759             * @param  parentOrganizationId the primary key of organization's parent
1760             *         organization
1761             * @param  name the organization's name
1762             * @param  type the organization's type
1763             * @param  regionId the primary key of the organization's region
1764             * @param  countryId the primary key of the organization's country
1765             * @param  statusId the organization's workflow status
1766             * @param  comments the comments about the organization
1767             * @param  logo whether to update the ogranization's logo
1768             * @param  logoBytes the new logo image data
1769             * @param  site whether the organization is to be associated with a main
1770             *         site
1771             * @param  serviceContext the service context to be applied (optionally
1772             *         <code>null</code>). Can set asset category IDs and asset tag
1773             *         names for the organization, and merge expando bridge attributes
1774             *         for the organization.
1775             * @return the organization
1776             * @throws PortalException if an organization or parent organization with
1777             *         the primary key could not be found or if the new information was
1778             *         invalid
1779             */
1780            @Override
1781            public Organization updateOrganization(
1782                            long companyId, long organizationId, long parentOrganizationId,
1783                            String name, String type, long regionId, long countryId,
1784                            long statusId, String comments, boolean logo, byte[] logoBytes,
1785                            boolean site, ServiceContext serviceContext)
1786                    throws PortalException {
1787    
1788                    // Organization
1789    
1790                    parentOrganizationId = getParentOrganizationId(
1791                            companyId, parentOrganizationId);
1792    
1793                    validate(
1794                            companyId, organizationId, parentOrganizationId, name, type,
1795                            countryId, statusId);
1796    
1797                    Organization organization = organizationPersistence.findByPrimaryKey(
1798                            organizationId);
1799    
1800                    long oldParentOrganizationId = organization.getParentOrganizationId();
1801                    String oldName = organization.getName();
1802    
1803                    organization.setParentOrganizationId(parentOrganizationId);
1804                    organization.setTreePath(organization.buildTreePath());
1805                    organization.setName(name);
1806                    organization.setType(type);
1807                    organization.setRecursable(true);
1808                    organization.setRegionId(regionId);
1809                    organization.setCountryId(countryId);
1810                    organization.setStatusId(statusId);
1811                    organization.setComments(comments);
1812    
1813                    PortalUtil.updateImageId(
1814                            organization, logo, logoBytes, "logoId",
1815                            PrefsPropsUtil.getLong(PropsKeys.USERS_IMAGE_MAX_SIZE),
1816                            PropsValues.USERS_IMAGE_MAX_HEIGHT,
1817                            PropsValues.USERS_IMAGE_MAX_WIDTH);
1818    
1819                    organization.setExpandoBridgeAttributes(serviceContext);
1820    
1821                    organizationPersistence.update(organization);
1822    
1823                    // Group
1824    
1825                    Group group = organization.getGroup();
1826    
1827                    long parentGroupId = group.getParentGroupId();
1828    
1829                    boolean createSite = false;
1830    
1831                    if (!group.isSite() && site) {
1832                            createSite = true;
1833                    }
1834    
1835                    boolean organizationGroup = isOrganizationGroup(
1836                            oldParentOrganizationId, group.getParentGroupId());
1837    
1838                    if (createSite || organizationGroup) {
1839                            if (parentOrganizationId !=
1840                                            OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
1841    
1842                                    Organization parentOrganization =
1843                                            organizationPersistence.fetchByPrimaryKey(
1844                                                    parentOrganizationId);
1845    
1846                                    Group parentGroup = parentOrganization.getGroup();
1847    
1848                                    if (site && parentGroup.isSite()) {
1849                                            parentGroupId = parentOrganization.getGroupId();
1850                                    }
1851                                    else {
1852                                            parentGroupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
1853                                    }
1854                            }
1855                            else {
1856                                    parentGroupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
1857                            }
1858                    }
1859    
1860                    if (createSite || !oldName.equals(name) || organizationGroup) {
1861                            groupLocalService.updateGroup(
1862                                    group.getGroupId(), parentGroupId, getLocalizationMap(name),
1863                                    group.getDescriptionMap(), group.getType(),
1864                                    group.isManualMembership(), group.getMembershipRestriction(),
1865                                    group.getFriendlyURL(), group.isInheritContent(),
1866                                    group.isActive(), null);
1867                    }
1868    
1869                    if (group.isSite() != site) {
1870                            groupLocalService.updateSite(group.getGroupId(), site);
1871                    }
1872    
1873                    // Organizations
1874    
1875                    if (createSite) {
1876                            List<Organization> childOrganizations =
1877                                    organizationLocalService.getOrganizations(
1878                                            companyId, organizationId);
1879    
1880                            for (Organization childOrganization : childOrganizations) {
1881                                    Group childGroup = childOrganization.getGroup();
1882    
1883                                    if (childGroup.isSite() &&
1884                                            (childGroup.getParentGroupId() ==
1885                                                    GroupConstants.DEFAULT_PARENT_GROUP_ID)) {
1886    
1887                                            childGroup.setParentGroupId(group.getGroupId());
1888    
1889                                            groupLocalService.updateGroup(childGroup);
1890                                    }
1891                            }
1892                    }
1893    
1894                    // Asset
1895    
1896                    if (serviceContext != null) {
1897                            updateAsset(
1898                                    serviceContext.getUserId(), organization,
1899                                    serviceContext.getAssetCategoryIds(),
1900                                    serviceContext.getAssetTagNames());
1901                    }
1902    
1903                    // Indexer
1904    
1905                    Indexer<Organization> indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1906                            Organization.class);
1907    
1908                    if (oldParentOrganizationId != parentOrganizationId) {
1909                            long[] reindexOrganizationIds = getReindexOrganizationIds(
1910                                    organization);
1911    
1912                            List<Organization> reindexOrganizations = new ArrayList<>(
1913                                    reindexOrganizationIds.length);
1914    
1915                            for (long reindexOrganizationId : reindexOrganizationIds) {
1916                                    Organization reindexOrganization = fetchOrganization(
1917                                            reindexOrganizationId);
1918    
1919                                    reindexOrganizations.add(reindexOrganization);
1920                            }
1921    
1922                            indexer.reindex(reindexOrganizations);
1923                    }
1924                    else {
1925                            indexer.reindex(organization);
1926                    }
1927    
1928                    return organization;
1929            }
1930    
1931            /**
1932             * Updates the organization.
1933             *
1934             * @param      companyId the primary key of the organization's company
1935             * @param      organizationId the primary key of the organization
1936             * @param      parentOrganizationId the primary key of organization's parent
1937             *             organization
1938             * @param      name the organization's name
1939             * @param      type the organization's type
1940             * @param      regionId the primary key of the organization's region
1941             * @param      countryId the primary key of the organization's country
1942             * @param      statusId the organization's workflow status
1943             * @param      comments the comments about the organization
1944             * @param      site whether the organization is to be associated with a main
1945             *             site
1946             * @param      serviceContext the service context to be applied (optionally
1947             *             <code>null</code>). Can set asset category IDs and asset tag
1948             *             names for the organization, and merge expando bridge
1949             *             attributes for the organization.
1950             * @return     the organization
1951             * @throws     PortalException if an organization or parent organization
1952             *             with the primary key could not be found or if the new
1953             *             information was invalid
1954             * @deprecated As of 7.0.0, replaced by {@link #updateOrganization(long,
1955             *             long, long, String, String, long, long, int, String, boolean,
1956             *             byte[], boolean, ServiceContext)}
1957             */
1958            @Deprecated
1959            @Override
1960            public Organization updateOrganization(
1961                            long companyId, long organizationId, long parentOrganizationId,
1962                            String name, String type, long regionId, long countryId,
1963                            long statusId, String comments, boolean site,
1964                            ServiceContext serviceContext)
1965                    throws PortalException {
1966    
1967                    return updateOrganization(
1968                            companyId, organizationId, parentOrganizationId, name, type,
1969                            regionId, countryId, statusId, comments, site, serviceContext);
1970            }
1971    
1972            protected void addSuborganizations(
1973                    List<Organization> allSuborganizations,
1974                    List<Organization> organizations) {
1975    
1976                    for (Organization organization : organizations) {
1977                            if (!allSuborganizations.contains(organization)) {
1978                                    allSuborganizations.add(organization);
1979    
1980                                    List<Organization> suborganizations =
1981                                            organizationPersistence.findByC_P(
1982                                                    organization.getCompanyId(),
1983                                                    organization.getOrganizationId());
1984    
1985                                    addSuborganizations(allSuborganizations, suborganizations);
1986                            }
1987                    }
1988            }
1989    
1990            protected SearchContext buildSearchContext(
1991                    long companyId, long parentOrganizationId, String name, String type,
1992                    String street, String city, String zip, Long regionId, Long countryId,
1993                    LinkedHashMap<String, Object> params, boolean andSearch, int start,
1994                    int end, Sort sort) {
1995    
1996                    String regionCode = null;
1997    
1998                    if (regionId != null) {
1999                            Region region = regionService.fetchRegion(regionId);
2000    
2001                            regionCode = region.getRegionCode();
2002                    }
2003    
2004                    String countryName = null;
2005    
2006                    if (countryId != null) {
2007                            Country country = countryService.fetchCountry(countryId);
2008    
2009                            countryName = country.getName();
2010                    }
2011    
2012                    return buildSearchContext(
2013                            companyId, parentOrganizationId, name, type, street, city, zip,
2014                            regionCode, countryName, params, andSearch, start, end, sort);
2015            }
2016    
2017            protected SearchContext buildSearchContext(
2018                    long companyId, long parentOrganizationId, String name, String type,
2019                    String street, String city, String zip, String region, String country,
2020                    LinkedHashMap<String, Object> params, boolean andSearch, int start,
2021                    int end, Sort sort) {
2022    
2023                    SearchContext searchContext = new SearchContext();
2024    
2025                    searchContext.setAndSearch(andSearch);
2026    
2027                    Map<String, Serializable> attributes = new HashMap<>();
2028    
2029                    attributes.put("city", city);
2030                    attributes.put("country", country);
2031                    attributes.put("name", name);
2032                    attributes.put("params", params);
2033                    attributes.put(
2034                            "parentOrganizationId", String.valueOf(parentOrganizationId));
2035                    attributes.put("region", region);
2036                    attributes.put("street", street);
2037                    attributes.put("type", type);
2038                    attributes.put("zip", zip);
2039    
2040                    searchContext.setAttributes(attributes);
2041    
2042                    searchContext.setCompanyId(companyId);
2043                    searchContext.setEnd(end);
2044    
2045                    if (params != null) {
2046                            String keywords = (String)params.remove("keywords");
2047    
2048                            if (Validator.isNotNull(keywords)) {
2049                                    searchContext.setKeywords(keywords);
2050                            }
2051                    }
2052    
2053                    if (sort != null) {
2054                            searchContext.setSorts(sort);
2055                    }
2056    
2057                    searchContext.setStart(start);
2058    
2059                    QueryConfig queryConfig = searchContext.getQueryConfig();
2060    
2061                    queryConfig.setHighlightEnabled(false);
2062                    queryConfig.setScoreEnabled(false);
2063    
2064                    return searchContext;
2065            }
2066    
2067            protected long getParentOrganizationId(
2068                    long companyId, long parentOrganizationId) {
2069    
2070                    if (parentOrganizationId !=
2071                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
2072    
2073                            // Ensure parent organization exists and belongs to the proper
2074                            // company
2075    
2076                            Organization parentOrganization =
2077                                    organizationPersistence.fetchByPrimaryKey(parentOrganizationId);
2078    
2079                            if ((parentOrganization == null) ||
2080                                    (companyId != parentOrganization.getCompanyId())) {
2081    
2082                                    parentOrganizationId =
2083                                            OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID;
2084                            }
2085                    }
2086    
2087                    return parentOrganizationId;
2088            }
2089    
2090            protected long[] getReindexOrganizationIds(Organization organization)
2091                    throws PortalException {
2092    
2093                    List<Organization> organizations = organizationPersistence.findByC_T(
2094                            organization.getCompanyId(),
2095                            CustomSQLUtil.keywords(organization.getTreePath())[0],
2096                            QueryUtil.ALL_POS, QueryUtil.ALL_POS,
2097                            new OrganizationNameComparator(true));
2098    
2099                    long[] organizationIds = new long[organizations.size()];
2100    
2101                    for (int i = 0; i < organizations.size(); i++) {
2102                            Organization curOrganization = organizations.get(i);
2103    
2104                            curOrganization.setTreePath(curOrganization.buildTreePath());
2105    
2106                            organizationPersistence.update(curOrganization);
2107    
2108                            organizationIds[i] = curOrganization.getOrganizationId();
2109                    }
2110    
2111                    if (!ArrayUtil.contains(
2112                                    organizationIds, organization.getOrganizationId())) {
2113    
2114                            organizationIds = ArrayUtil.append(
2115                                    organizationIds, organization.getOrganizationId());
2116                    }
2117    
2118                    return organizationIds;
2119            }
2120    
2121            protected boolean isOrganizationGroup(long organizationId, long groupId) {
2122                    if ((organizationId ==
2123                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) &&
2124                            (groupId == GroupConstants.DEFAULT_PARENT_GROUP_ID)) {
2125    
2126                            return true;
2127                    }
2128    
2129                    if (organizationId !=
2130                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
2131    
2132                            Organization organization =
2133                                    organizationPersistence.fetchByPrimaryKey(organizationId);
2134    
2135                            if (organization.getGroupId() == groupId) {
2136                                    return true;
2137                            }
2138                    }
2139    
2140                    return false;
2141            }
2142    
2143            protected boolean isParentOrganization(
2144                            long parentOrganizationId, long organizationId)
2145                    throws PortalException {
2146    
2147                    // Return true if parentOrganizationId is among the parent organizatons
2148                    // of organizationId
2149    
2150                    if (organizationId ==
2151                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
2152    
2153                            return false;
2154                    }
2155    
2156                    Organization organization = organizationPersistence.findByPrimaryKey(
2157                            organizationId);
2158    
2159                    String treePath = organization.getTreePath();
2160    
2161                    if (treePath.contains(
2162                                    StringPool.SLASH + parentOrganizationId + StringPool.SLASH)) {
2163    
2164                            return true;
2165                    }
2166                    else {
2167                            return false;
2168                    }
2169            }
2170    
2171            protected boolean isUseCustomSQL(LinkedHashMap<String, Object> params) {
2172                    if (MapUtil.isEmpty(params)) {
2173                            return false;
2174                    }
2175    
2176                    return true;
2177            }
2178    
2179            protected void validate(
2180                            long companyId, long organizationId, long parentOrganizationId,
2181                            String name, String type, long countryId, long statusId)
2182                    throws PortalException {
2183    
2184                    if (!ArrayUtil.contains(PropsValues.ORGANIZATIONS_TYPES, type)) {
2185                            throw new OrganizationTypeException(
2186                                    "Invalid organization type " + type);
2187                    }
2188    
2189                    if (parentOrganizationId ==
2190                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
2191    
2192                            if (!OrganizationImpl.isRootable(type)) {
2193                                    throw new OrganizationParentException(
2194                                            "Organization of type " + type + " cannot be a root");
2195                            }
2196                    }
2197                    else {
2198                            Organization parentOrganization =
2199                                    organizationPersistence.fetchByPrimaryKey(parentOrganizationId);
2200    
2201                            if (parentOrganization == null) {
2202                                    throw new OrganizationParentException(
2203                                            "Organization " + parentOrganizationId + " doesn't exist");
2204                            }
2205    
2206                            String[] childrenTypes = OrganizationImpl.getChildrenTypes(
2207                                    parentOrganization.getType());
2208    
2209                            if (childrenTypes.length == 0) {
2210                                    throw new OrganizationParentException(
2211                                            "Organization of type " + type + " cannot have children");
2212                            }
2213    
2214                            if ((companyId != parentOrganization.getCompanyId()) ||
2215                                    (parentOrganizationId == organizationId)) {
2216    
2217                                    throw new OrganizationParentException();
2218                            }
2219    
2220                            if (!ArrayUtil.contains(childrenTypes, type)) {
2221                                    throw new OrganizationParentException(
2222                                            "Type " + type + " not allowed as child of " +
2223                                                    parentOrganization.getType());
2224                            }
2225                    }
2226    
2227                    if ((organizationId > 0) &&
2228                            (parentOrganizationId !=
2229                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID)) {
2230    
2231                            // Prevent circular organizational references
2232    
2233                            if (isParentOrganization(organizationId, parentOrganizationId)) {
2234                                    throw new OrganizationParentException();
2235                            }
2236                    }
2237    
2238                    if (Validator.isNull(name)) {
2239                            throw new OrganizationNameException();
2240                    }
2241                    else {
2242                            Organization organization = organizationPersistence.fetchByC_N(
2243                                    companyId, name);
2244    
2245                            if ((organization != null) &&
2246                                    StringUtil.equalsIgnoreCase(organization.getName(), name)) {
2247    
2248                                    if ((organizationId <= 0) ||
2249                                            (organization.getOrganizationId() != organizationId)) {
2250    
2251                                            throw new DuplicateOrganizationException(
2252                                                    "There is another organization named " + name);
2253                                    }
2254                            }
2255                    }
2256    
2257                    boolean countryRequired = GetterUtil.getBoolean(
2258                            PropsUtil.get(
2259                                    PropsKeys.ORGANIZATIONS_COUNTRY_REQUIRED, new Filter(type)));
2260    
2261                    if (countryRequired || (countryId > 0)) {
2262                            countryPersistence.findByPrimaryKey(countryId);
2263                    }
2264    
2265                    listTypeService.validate(
2266                            statusId, ListTypeConstants.ORGANIZATION_STATUS);
2267            }
2268    
2269            protected void validate(
2270                            long companyId, long parentOrganizationId, String name, String type,
2271                            long countryId, long statusId)
2272                    throws PortalException {
2273    
2274                    validate(
2275                            companyId, 0, parentOrganizationId, name, type, countryId,
2276                            statusId);
2277            }
2278    
2279    }