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