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