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