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