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.Date;
080    import java.util.HashMap;
081    import java.util.HashSet;
082    import java.util.Iterator;
083    import java.util.LinkedHashMap;
084    import java.util.List;
085    import java.util.Map;
086    import java.util.Set;
087    
088    /**
089     * Provides the local service for accessing, adding, deleting, and updating
090     * organizations.
091     *
092     * @author Brian Wing Shun Chan
093     * @author Jorge Ferrer
094     * @author Julio Camarero
095     * @author Hugo Huijser
096     * @author Juan Fern??ndez
097     */
098    public class OrganizationLocalServiceImpl
099            extends OrganizationLocalServiceBaseImpl {
100    
101            /**
102             * Adds the organizations to the group.
103             *
104             * @param  groupId the primary key of the group
105             * @param  organizationIds the primary keys of the organizations
106             * @throws PortalException if a group or organization with the primary key
107             *         could not be found
108             */
109            @Override
110            public void addGroupOrganizations(long groupId, long[] organizationIds)
111                    throws PortalException {
112    
113                    groupPersistence.addOrganizations(groupId, organizationIds);
114    
115                    PermissionCacheUtil.clearCache();
116            }
117    
118            /**
119             * Adds an organization.
120             *
121             * <p>
122             * This method handles the creation and bookkeeping of the organization
123             * including its resources, metadata, and internal data structures. It is
124             * not necessary to make a subsequent call to {@link
125             * #addOrganizationResources(long, Organization)}.
126             * </p>
127             *
128             * @param  userId the primary key of the creator/owner of the organization
129             * @param  parentOrganizationId the primary key of the organization's parent
130             *         organization
131             * @param  name the organization's name
132             * @param  site whether the organization is to be associated with a main
133             *         site
134             * @return the organization
135             * @throws PortalException if a creator or parent organization with the
136             *         primary key could not be found or if the organization's
137             *         information was invalid
138             */
139            @Override
140            public Organization addOrganization(
141                            long userId, long parentOrganizationId, String name, boolean site)
142                    throws PortalException {
143    
144                    return addOrganization(
145                            userId, parentOrganizationId, name,
146                            OrganizationConstants.TYPE_REGULAR_ORGANIZATION, 0, 0,
147                            ListTypeConstants.ORGANIZATION_STATUS_DEFAULT, StringPool.BLANK,
148                            site, null);
149            }
150    
151            /**
152             * Adds an organization.
153             *
154             * <p>
155             * This method handles the creation and bookkeeping of the organization
156             * including its resources, metadata, and internal data structures. It is
157             * not necessary to make a subsequent call to {@link
158             * #addOrganizationResources(long, Organization)}.
159             * </p>
160             *
161             * @param      userId the primary key of the creator/owner of the
162             *             organization
163             * @param      parentOrganizationId the primary key of the organization's
164             *             parent organization
165             * @param      name the organization's name
166             * @param      type the organization's type
167             * @param      recursable whether the permissions of the organization are to
168             *             be inherited by its suborganizations
169             * @param      regionId the primary key of the organization's region
170             * @param      countryId the primary key of the organization's country
171             * @param      statusId the organization's workflow status
172             * @param      comments the comments about the organization
173             * @param      site whether the organization is to be associated with a main
174             *             site
175             * @param      serviceContext the service context to be applied (optionally
176             *             <code>null</code>). Can set asset category IDs, asset tag
177             *             names, and expando bridge attributes for the organization.
178             * @return     the organization
179             * @throws     PortalException if a creator or parent organization with the
180             *             primary key could not be found or if the organization's
181             *             information was invalid
182             * @deprecated As of 6.2.0, replaced by {@link #addOrganization(long, long,
183             *             String, String, long, long, int, String, boolean,
184             *             ServiceContext)}
185             */
186            @Deprecated
187            @Override
188            public Organization addOrganization(
189                            long userId, long parentOrganizationId, String name, String type,
190                            boolean recursable, long regionId, long countryId, int statusId,
191                            String comments, boolean site, ServiceContext serviceContext)
192                    throws PortalException {
193    
194                    return addOrganization(
195                            userId, parentOrganizationId, name, type, regionId, countryId,
196                            statusId, comments, site, serviceContext);
197            }
198    
199            /**
200             * Adds an organization.
201             *
202             * <p>
203             * This method handles the creation and bookkeeping of the organization
204             * including its resources, metadata, and internal data structures. It is
205             * not necessary to make a subsequent call to {@link
206             * #addOrganizationResources(long, Organization)}.
207             * </p>
208             *
209             * @param  userId the primary key of the creator/owner of the organization
210             * @param  parentOrganizationId the primary key of the organization's parent
211             *         organization
212             * @param  name the organization's name
213             * @param  type the organization's type
214             * @param  regionId the primary key of the organization's region
215             * @param  countryId the primary key of the organization's country
216             * @param  statusId the organization's workflow status
217             * @param  comments the comments about the organization
218             * @param  site whether the organization is to be associated with a main
219             *         site
220             * @param  serviceContext the service context to be applied (optionally
221             *         <code>null</code>). Can set asset category IDs, asset tag names,
222             *         and expando bridge attributes for the organization.
223             * @return the organization
224             * @throws PortalException if a creator or parent organization with the
225             *         primary key could not be found or if the organization's
226             *         information was invalid
227             */
228            @Override
229            public Organization addOrganization(
230                            long userId, long parentOrganizationId, String name, String type,
231                            long regionId, long countryId, int statusId, String comments,
232                            boolean site, ServiceContext serviceContext)
233                    throws PortalException {
234    
235                    // Organization
236    
237                    User user = userPersistence.findByPrimaryKey(userId);
238                    parentOrganizationId = getParentOrganizationId(
239                            user.getCompanyId(), parentOrganizationId);
240                    Date now = new Date();
241    
242                    validate(
243                            user.getCompanyId(), parentOrganizationId, name, type, countryId,
244                            statusId);
245    
246                    long organizationId = counterLocalService.increment();
247    
248                    Organization organization = organizationPersistence.create(
249                            organizationId);
250    
251                    if (serviceContext != null) {
252                            organization.setUuid(serviceContext.getUuid());
253                    }
254    
255                    organization.setCompanyId(user.getCompanyId());
256                    organization.setUserId(user.getUserId());
257                    organization.setUserName(user.getFullName());
258    
259                    if (serviceContext != null) {
260                            organization.setCreateDate(serviceContext.getCreateDate(now));
261                            organization.setModifiedDate(serviceContext.getModifiedDate(now));
262                    }
263                    else {
264                            organization.setCreateDate(now);
265                            organization.setModifiedDate(now);
266                    }
267    
268                    organization.setParentOrganizationId(parentOrganizationId);
269                    organization.setTreePath(organization.buildTreePath());
270                    organization.setName(name);
271                    organization.setType(type);
272                    organization.setRecursable(true);
273                    organization.setRegionId(regionId);
274                    organization.setCountryId(countryId);
275                    organization.setStatusId(statusId);
276                    organization.setComments(comments);
277                    organization.setExpandoBridgeAttributes(serviceContext);
278    
279                    organizationPersistence.update(organization);
280    
281                    // Group
282    
283                    long parentGroupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
284    
285                    if (parentOrganizationId !=
286                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
287    
288                            Organization parentOrganization =
289                                    organizationPersistence.fetchByPrimaryKey(parentOrganizationId);
290    
291                            if (parentOrganization != null) {
292                                    Group parentGroup = parentOrganization.getGroup();
293    
294                                    if (site && parentGroup.isSite()) {
295                                            parentGroupId = parentOrganization.getGroupId();
296                                    }
297                            }
298                    }
299    
300                    Group group = groupLocalService.addGroup(
301                            userId, parentGroupId, Organization.class.getName(), organizationId,
302                            GroupConstants.DEFAULT_LIVE_GROUP_ID, name, null,
303                            GroupConstants.TYPE_SITE_PRIVATE, false,
304                            GroupConstants.DEFAULT_MEMBERSHIP_RESTRICTION, null, site, true,
305                            null);
306    
307                    // Role
308    
309                    Role role = roleLocalService.getRole(
310                            organization.getCompanyId(), RoleConstants.ORGANIZATION_OWNER);
311    
312                    userGroupRoleLocalService.addUserGroupRoles(
313                            userId, group.getGroupId(), new long[] {role.getRoleId()});
314    
315                    // Resources
316    
317                    addOrganizationResources(userId, organization);
318    
319                    // Asset
320    
321                    if (serviceContext != null) {
322                            updateAsset(
323                                    userId, organization, serviceContext.getAssetCategoryIds(),
324                                    serviceContext.getAssetTagNames());
325                    }
326    
327                    // Indexer
328    
329                    if ((serviceContext == null) || serviceContext.isIndexingEnabled()) {
330                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
331                                    Organization.class);
332    
333                            indexer.reindex(organization);
334                    }
335    
336                    return organization;
337            }
338    
339            /**
340             * Adds a resource for each type of permission available on the
341             * organization.
342             *
343             * @param  userId the primary key of the creator/owner of the organization
344             * @param  organization the organization
345             * @throws PortalException if a portal exception occurred
346             */
347            @Override
348            public void addOrganizationResources(long userId, Organization organization)
349                    throws PortalException {
350    
351                    String name = Organization.class.getName();
352    
353                    resourceLocalService.addResources(
354                            organization.getCompanyId(), 0, userId, name,
355                            organization.getOrganizationId(), false, false, false);
356            }
357    
358            /**
359             * Assigns the password policy to the organizations, removing any other
360             * currently assigned password policies.
361             *
362             * @param passwordPolicyId the primary key of the password policy
363             * @param organizationIds the primary keys of the organizations
364             */
365            @Override
366            public void addPasswordPolicyOrganizations(
367                    long passwordPolicyId, long[] organizationIds) {
368    
369                    passwordPolicyRelLocalService.addPasswordPolicyRels(
370                            passwordPolicyId, Organization.class.getName(), organizationIds);
371            }
372    
373            /**
374             * Deletes the organization's logo.
375             *
376             * @param  organizationId the primary key of the organization
377             * @throws PortalException if an organization or parent organization with
378             *         the primary key could not be found or if the organization's logo
379             *         could not be found
380             */
381            @Override
382            public void deleteLogo(long organizationId) throws PortalException {
383                    Organization organization = getOrganization(organizationId);
384    
385                    PortalUtil.updateImageId(organization, false, null, "logoId", 0, 0, 0);
386            }
387    
388            /**
389             * Deletes the organization. The organization's associated resources and
390             * assets are also deleted.
391             *
392             * @param  organizationId the primary key of the organization
393             * @return the deleted organization
394             * @throws PortalException if an organization with the primary key could not
395             *         be found, if the organization had a workflow in approved status,
396             *         or if the organization was a parent organization
397             */
398            @Override
399            public Organization deleteOrganization(long organizationId)
400                    throws PortalException {
401    
402                    Organization organization = organizationPersistence.findByPrimaryKey(
403                            organizationId);
404    
405                    return organizationLocalService.deleteOrganization(organization);
406            }
407    
408            /**
409             * Deletes the organization. The organization's associated resources and
410             * assets are also deleted.
411             *
412             * @param  organization the organization
413             * @return the deleted organization
414             * @throws PortalException if the organization had a workflow in approved
415             *         status or if the organization was a parent organization
416             */
417            @Override
418            @SystemEvent(type = SystemEventConstants.TYPE_DELETE)
419            public Organization deleteOrganization(Organization organization)
420                    throws PortalException {
421    
422                    if ((userLocalService.getOrganizationUsersCount(
423                                    organization.getOrganizationId(),
424                                    WorkflowConstants.STATUS_APPROVED) > 0) ||
425                            (organizationPersistence.countByC_P(
426                                    organization.getCompanyId(),
427                                    organization.getOrganizationId()) > 0)) {
428    
429                            throw new RequiredOrganizationException();
430                    }
431    
432                    // Asset
433    
434                    assetEntryLocalService.deleteEntry(
435                            Organization.class.getName(), organization.getOrganizationId());
436    
437                    // Addresses
438    
439                    addressLocalService.deleteAddresses(
440                            organization.getCompanyId(), Organization.class.getName(),
441                            organization.getOrganizationId());
442    
443                    // Email addresses
444    
445                    emailAddressLocalService.deleteEmailAddresses(
446                            organization.getCompanyId(), Organization.class.getName(),
447                            organization.getOrganizationId());
448    
449                    // Expando
450    
451                    expandoRowLocalService.deleteRows(organization.getOrganizationId());
452    
453                    // Password policy relation
454    
455                    passwordPolicyRelLocalService.deletePasswordPolicyRel(
456                            Organization.class.getName(), organization.getOrganizationId());
457    
458                    // Phone
459    
460                    phoneLocalService.deletePhones(
461                            organization.getCompanyId(), Organization.class.getName(),
462                            organization.getOrganizationId());
463    
464                    // Website
465    
466                    websiteLocalService.deleteWebsites(
467                            organization.getCompanyId(), Organization.class.getName(),
468                            organization.getOrganizationId());
469    
470                    // Group
471    
472                    Group group = organization.getGroup();
473    
474                    if (group.isSite()) {
475                            group.setSite(false);
476    
477                            groupPersistence.update(group);
478                    }
479    
480                    groupLocalService.deleteGroup(group);
481    
482                    // Resources
483    
484                    String name = Organization.class.getName();
485    
486                    resourceLocalService.deleteResource(
487                            organization.getCompanyId(), name,
488                            ResourceConstants.SCOPE_INDIVIDUAL,
489                            organization.getOrganizationId());
490    
491                    // Organization
492    
493                    organizationPersistence.remove(organization);
494    
495                    // Permission cache
496    
497                    PermissionCacheUtil.clearCache();
498    
499                    return organization;
500            }
501    
502            /**
503             * Returns the organization with the name.
504             *
505             * @param  companyId the primary key of the organization's company
506             * @param  name the organization's name
507             * @return the organization with the name, or <code>null</code> if no
508             *         organization could be found
509             */
510            @Override
511            public Organization fetchOrganization(long companyId, String name) {
512                    return organizationPersistence.fetchByC_N(companyId, name);
513            }
514    
515            @Override
516            public List<Organization> getGroupUserOrganizations(
517                            long groupId, long userId)
518                    throws PortalException {
519    
520                    long[] groupOrganizationIds =
521                            groupPersistence.getOrganizationPrimaryKeys(groupId);
522    
523                    if (groupOrganizationIds.length == 0) {
524                            return Collections.emptyList();
525                    }
526    
527                    long[] userOrganizationIds = userPersistence.getOrganizationPrimaryKeys(
528                            userId);
529    
530                    if (userOrganizationIds.length == 0) {
531                            return Collections.emptyList();
532                    }
533    
534                    Set<Long> organizationIds = SetUtil.intersect(
535                            groupOrganizationIds, userOrganizationIds);
536    
537                    if (organizationIds.isEmpty()) {
538                            return Collections.emptyList();
539                    }
540    
541                    List<Organization> organizations = new ArrayList<Organization>(
542                            organizationIds.size());
543    
544                    for (Long organizationId : organizationIds) {
545                            organizations.add(
546                                    organizationPersistence.findByPrimaryKey(organizationId));
547                    }
548    
549                    return organizations;
550            }
551    
552            @Override
553            public List<Organization> getNoAssetOrganizations() {
554                    return organizationFinder.findByNoAssets();
555            }
556    
557            /**
558             * Returns the organization with the name.
559             *
560             * @param  companyId the primary key of the organization's company
561             * @param  name the organization's name
562             * @return the organization with the name
563             * @throws PortalException if the organization with the name could not be
564             *         found
565             */
566            @Override
567            public Organization getOrganization(long companyId, String name)
568                    throws PortalException {
569    
570                    return organizationPersistence.findByC_N(companyId, name);
571            }
572    
573            /**
574             * Returns the primary key of the organization with the name.
575             *
576             * @param  companyId the primary key of the organization's company
577             * @param  name the organization's name
578             * @return the primary key of the organization with the name, or
579             *         <code>0</code> if the organization could not be found
580             */
581            @Override
582            public long getOrganizationId(long companyId, String name) {
583                    Organization organization = organizationPersistence.fetchByC_N(
584                            companyId, name);
585    
586                    if (organization != null) {
587                            return organization.getOrganizationId();
588                    }
589                    else {
590                            return 0;
591                    }
592            }
593    
594            @Override
595            public List<Organization> getOrganizations(
596                            long userId, int start, int end,
597                            OrderByComparator<Organization> obc)
598                    throws PortalException {
599    
600                    User user = userPersistence.findByPrimaryKey(userId);
601    
602                    List<Organization> organizations = ListUtil.copy(
603                            userPersistence.getOrganizations(userId));
604    
605                    Iterator<Organization> iterator = organizations.iterator();
606    
607                    while (iterator.hasNext()) {
608                            Organization organization = iterator.next();
609    
610                            if (organization.getCompanyId() != user.getCompanyId()) {
611                                    iterator.remove();
612                            }
613                    }
614    
615                    if (organizations.isEmpty()) {
616                            return organizations;
617                    }
618    
619                    if (obc == null) {
620                            obc = new OrganizationNameComparator(true);
621                    }
622    
623                    Collections.sort(organizations, obc);
624    
625                    return ListUtil.subList(organizations, start, end);
626            }
627    
628            /**
629             * Returns all the organizations belonging to the parent organization.
630             *
631             * @param  companyId the primary key of the organization's company
632             * @param  parentOrganizationId the primary key of the organization's parent
633             *         organization
634             * @return the organizations belonging to the parent organization
635             */
636            @Override
637            public List<Organization> getOrganizations(
638                    long companyId, long parentOrganizationId) {
639    
640                    return getOrganizations(
641                            companyId, parentOrganizationId, QueryUtil.ALL_POS,
642                            QueryUtil.ALL_POS);
643            }
644    
645            /**
646             * Returns a range of all the organizations belonging to the parent
647             * organization.
648             *
649             * <p>
650             * Useful when paginating results. Returns a maximum of <code>end -
651             * start</code> instances. <code>start</code> and <code>end</code> are not
652             * primary keys, they are indexes in the result set. Thus, <code>0</code>
653             * refers to the first result in the set. Setting both <code>start</code>
654             * and <code>end</code> to {@link
655             * com.liferay.portal.kernel.dao.orm.QueryUtil#ALL_POS} will return the full
656             * result set.
657             * </p>
658             *
659             * @param  companyId the primary key of the organization's company
660             * @param  parentOrganizationId the primary key of the organization's parent
661             *         organization
662             * @param  start the lower bound of the range of organizations to return
663             * @param  end the upper bound of the range of organizations to return (not
664             *         inclusive)
665             * @return the range of organizations belonging to the parent organization
666             * @see    com.liferay.portal.service.persistence.OrganizationPersistence#findByC_P(
667             *         long, long, int, int)
668             */
669            @Override
670            public List<Organization> getOrganizations(
671                    long companyId, long parentOrganizationId, int start, int end) {
672    
673                    if (parentOrganizationId ==
674                                    OrganizationConstants.ANY_PARENT_ORGANIZATION_ID) {
675    
676                            return organizationPersistence.findByCompanyId(
677                                    companyId, start, end);
678                    }
679                    else {
680                            return organizationPersistence.findByC_P(
681                                    companyId, parentOrganizationId, start, end);
682                    }
683            }
684    
685            /**
686             * Returns the organizations with the primary keys.
687             *
688             * @param  organizationIds the primary keys of the organizations
689             * @return the organizations with the primary keys
690             * @throws PortalException if any one of the organizations could not be
691             *         found
692             */
693            @Override
694            public List<Organization> getOrganizations(long[] organizationIds)
695                    throws PortalException {
696    
697                    List<Organization> organizations = new ArrayList<Organization>(
698                            organizationIds.length);
699    
700                    for (long organizationId : organizationIds) {
701                            Organization organization = getOrganization(organizationId);
702    
703                            organizations.add(organization);
704                    }
705    
706                    return organizations;
707            }
708    
709            /**
710             * Returns the number of organizations belonging to the parent organization.
711             *
712             * @param  companyId the primary key of the organization's company
713             * @param  parentOrganizationId the primary key of the organization's parent
714             *         organization
715             * @return the number of organizations belonging to the parent organization
716             */
717            @Override
718            public int getOrganizationsCount(
719                    long companyId, long parentOrganizationId) {
720    
721                    if (parentOrganizationId ==
722                                    OrganizationConstants.ANY_PARENT_ORGANIZATION_ID) {
723    
724                            return organizationPersistence.countByCompanyId(companyId);
725                    }
726                    else {
727                            return organizationPersistence.countByC_P(
728                                    companyId, parentOrganizationId);
729                    }
730            }
731    
732            /**
733             * Returns the parent organizations in order by closest ancestor. The list
734             * starts with the organization itself.
735             *
736             * @param  organizationId the primary key of the organization
737             * @return the parent organizations in order by closest ancestor
738             * @throws PortalException if an organization with the primary key could not
739             *         be found
740             */
741            @Override
742            public List<Organization> getParentOrganizations(long organizationId)
743                    throws PortalException {
744    
745                    if (organizationId ==
746                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
747    
748                            return new ArrayList<Organization>();
749                    }
750    
751                    Organization organization = organizationPersistence.findByPrimaryKey(
752                            organizationId);
753    
754                    return organization.getAncestors();
755            }
756    
757            /**
758             * Returns the suborganizations of the organizations.
759             *
760             * @param  organizations the organizations from which to get
761             *         suborganizations
762             * @return the suborganizations of the organizations
763             */
764            @Override
765            public List<Organization> getSuborganizations(
766                    List<Organization> organizations) {
767    
768                    List<Organization> allSuborganizations = new ArrayList<Organization>();
769    
770                    for (int i = 0; i < organizations.size(); i++) {
771                            Organization organization = organizations.get(i);
772    
773                            List<Organization> suborganizations =
774                                    organizationPersistence.findByC_P(
775                                            organization.getCompanyId(),
776                                            organization.getOrganizationId());
777    
778                            addSuborganizations(allSuborganizations, suborganizations);
779                    }
780    
781                    return allSuborganizations;
782            }
783    
784            /**
785             * Returns the suborganizations of the organization.
786             *
787             * @param  companyId the primary key of the organization's company
788             * @param  organizationId the primary key of the organization
789             * @return the suborganizations of the organization
790             */
791            @Override
792            public List<Organization> getSuborganizations(
793                    long companyId, long organizationId) {
794    
795                    return organizationPersistence.findByC_P(companyId, organizationId);
796            }
797    
798            /**
799             * Returns the count of suborganizations of the organization.
800             *
801             * @param  companyId the primary key of the organization's company
802             * @param  organizationId the primary key of the organization
803             * @return the count of suborganizations of the organization
804             */
805            @Override
806            public int getSuborganizationsCount(long companyId, long organizationId) {
807                    return organizationPersistence.countByC_P(companyId, organizationId);
808            }
809    
810            /**
811             * Returns the intersection of <code>allOrganizations</code> and
812             * <code>availableOrganizations</code>.
813             *
814             * @param  allOrganizations the organizations to check for availability
815             * @param  availableOrganizations the available organizations
816             * @return the intersection of <code>allOrganizations</code> and
817             *         <code>availableOrganizations</code>
818             */
819            @Override
820            public List<Organization> getSubsetOrganizations(
821                    List<Organization> allOrganizations,
822                    List<Organization> availableOrganizations) {
823    
824                    List<Organization> subsetOrganizations = new ArrayList<Organization>();
825    
826                    for (Organization organization : allOrganizations) {
827                            if (availableOrganizations.contains(organization)) {
828                                    subsetOrganizations.add(organization);
829                            }
830                    }
831    
832                    return subsetOrganizations;
833            }
834    
835            /**
836             * Returns all the organization IDs associated with the user. If
837             * <code>includeAdministrative</code> is <code>true</code>, the result
838             * includes those organization IDs that are indirectly associated to the
839             * user because he is an administrator or owner of the organization.
840             *
841             * @param  userId the primary key of the user
842             * @param  includeAdministrative whether to include organizations that are
843             *         indirectly associated to the user because he is an administrator
844             *         or owner of the organization
845             * @return the organization IDs of organizations associated with the user
846             * @throws PortalException if a user with the primary key could not be found
847             *         or if a portal exception occurred
848             * @throws SystemException if a system exception occurred
849             */
850            @Override
851            public long[] getUserOrganizationIds(
852                            long userId, boolean includeAdministrative)
853                    throws PortalException {
854    
855                    if (!includeAdministrative) {
856                            return userPersistence.getOrganizationPrimaryKeys(userId);
857                    }
858    
859                    Set<Long> organizationIds = SetUtil.fromArray(
860                            userPersistence.getOrganizationPrimaryKeys(userId));
861    
862                    List<UserGroupRole> userGroupRoles =
863                            userGroupRoleLocalService.getUserGroupRoles(userId);
864    
865                    for (UserGroupRole userGroupRole : userGroupRoles) {
866                            Role role = userGroupRole.getRole();
867    
868                            String roleName = role.getName();
869    
870                            if (roleName.equals(RoleConstants.ORGANIZATION_ADMINISTRATOR) ||
871                                    roleName.equals(RoleConstants.ORGANIZATION_OWNER)) {
872    
873                                    Group group = userGroupRole.getGroup();
874    
875                                    organizationIds.add(group.getOrganizationId());
876                            }
877                    }
878    
879                    return ArrayUtil.toLongArray(organizationIds);
880            }
881    
882            /**
883             * Returns all the organizations associated with the user. If
884             * <code>includeAdministrative</code> is <code>true</code>, the result
885             * includes those organizations that are indirectly associated to the user
886             * because he is an administrator or owner of the organization.
887             *
888             * @param  userId the primary key of the user
889             * @param  includeAdministrative whether to include organizations that are
890             *         indirectly associated to the user because he is an administrator
891             *         or owner of the organization
892             * @return the organizations associated with the user
893             * @throws PortalException if a user with the primary key could not be found
894             */
895            @Override
896            public List<Organization> getUserOrganizations(
897                            long userId, boolean includeAdministrative)
898                    throws PortalException {
899    
900                    if (!includeAdministrative) {
901                            return getUserOrganizations(userId);
902                    }
903    
904                    Set<Organization> organizations = new HashSet<Organization>(
905                            getUserOrganizations(userId));
906    
907                    List<UserGroupRole> userGroupRoles =
908                            userGroupRoleLocalService.getUserGroupRoles(userId);
909    
910                    for (UserGroupRole userGroupRole : userGroupRoles) {
911                            Role role = userGroupRole.getRole();
912    
913                            String roleName = role.getName();
914    
915                            if (roleName.equals(RoleConstants.ORGANIZATION_ADMINISTRATOR) ||
916                                    roleName.equals(RoleConstants.ORGANIZATION_OWNER)) {
917    
918                                    Group group = userGroupRole.getGroup();
919    
920                                    Organization organization =
921                                            organizationPersistence.findByPrimaryKey(
922                                                    group.getOrganizationId());
923    
924                                    organizations.add(organization);
925                            }
926                    }
927    
928                    return new ArrayList<Organization>(organizations);
929            }
930    
931            /**
932             * Returns <code>true</code> if the password policy has been assigned to the
933             * organization.
934             *
935             * @param  passwordPolicyId the primary key of the password policy
936             * @param  organizationId the primary key of the organization
937             * @return <code>true</code> if the password policy has been assigned to the
938             *         organization; <code>false</code> otherwise
939             */
940            @Override
941            public boolean hasPasswordPolicyOrganization(
942                    long passwordPolicyId, long organizationId) {
943    
944                    return passwordPolicyRelLocalService.hasPasswordPolicyRel(
945                            passwordPolicyId, Organization.class.getName(), organizationId);
946            }
947    
948            /**
949             * Returns <code>true</code> if the user is a member of the organization,
950             * optionally focusing on suborganizations or the specified organization.
951             * This method is usually called to determine if the user has view access to
952             * a resource belonging to the organization.
953             *
954             * <ol>
955             * <li>
956             * If <code>inheritSuborganizations=<code>false</code></code>:
957             * the method checks whether the user belongs to the organization specified
958             * by <code>organizationId</code>. The parameter
959             * <code>includeSpecifiedOrganization</code> is ignored.
960             * </li>
961             * <li>
962             * The parameter <code>includeSpecifiedOrganization</code> is
963             * ignored unless <code>inheritSuborganizations</code> is also
964             * <code>true</code>.
965             * </li>
966             * <li>
967             * If <code>inheritSuborganizations=<code>true</code></code> and
968             * <code>includeSpecifiedOrganization=<code>false</code></code>: the method
969             * checks
970             * whether the user belongs to one of the child organizations of the one
971             * specified by <code>organizationId</code>.
972             * </li>
973             * <li>
974             * If <code>inheritSuborganizations=<code>true</code></code> and
975             * <code>includeSpecifiedOrganization=<code>true</code></code>: the method
976             * checks whether
977             * the user belongs to the organization specified by
978             * <code>organizationId</code> or any of
979             * its child organizations.
980             * </li>
981             * </ol>
982             *
983             * @param  userId the primary key of the organization's user
984             * @param  organizationId the primary key of the organization
985             * @param  inheritSuborganizations if <code>true</code> suborganizations are
986             *         considered in the determination
987             * @param  includeSpecifiedOrganization if <code>true</code> the
988             *         organization specified by <code>organizationId</code> is
989             *         considered in the determination
990             * @return <code>true</code> if the user has access to the organization;
991             *         <code>false</code> otherwise
992             * @throws PortalException if an organization with the primary key could not
993             *         be found
994             * @see    com.liferay.portal.service.persistence.OrganizationFinder
995             */
996            @Override
997            public boolean hasUserOrganization(
998                            long userId, long organizationId, boolean inheritSuborganizations,
999                            boolean includeSpecifiedOrganization)
1000                    throws PortalException {
1001    
1002                    if (!inheritSuborganizations) {
1003                            return userPersistence.containsOrganization(userId, organizationId);
1004                    }
1005    
1006                    LinkedHashMap<String, Object> params =
1007                            new LinkedHashMap<String, Object>();
1008    
1009                    List<Organization> organizationsTree = new ArrayList<Organization>();
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                            Hits hits = indexer.search(searchContext);
1497    
1498                            return hits.getLength();
1499                    }
1500                    catch (Exception e) {
1501                            throw new SystemException(e);
1502                    }
1503            }
1504    
1505            /**
1506             * Returns the number of organizations with the type, region, and country,
1507             * and whose name, street, city, and zipcode match the keywords specified
1508             * for them.
1509             *
1510             * @param  companyId the primary key of the organization's company
1511             * @param  parentOrganizationId the primary key of the organization's parent
1512             *         organization
1513             * @param  name the name keywords (space separated, optionally
1514             *         <code>null</code>)
1515             * @param  type the organization's type (optionally <code>null</code>)
1516             * @param  street the street keywords (optionally <code>null</code>)
1517             * @param  city the city keywords (optionally <code>null</code>)
1518             * @param  zip the zipcode keywords (optionally <code>null</code>)
1519             * @param  regionId the primary key of the organization's region (optionally
1520             *         <code>null</code>)
1521             * @param  countryId the primary key of the organization's country
1522             *         (optionally <code>null</code>)
1523             * @param  params the finder parameters (optionally <code>null</code>). For
1524             *         more information see {@link
1525             *         com.liferay.portal.service.persistence.OrganizationFinder}
1526             * @param  andOperator whether every field must match its keywords, or just
1527             *         one field. For example, &quot;organizations with the name
1528             *         'Employees' and city 'Chicago'&quot; vs &quot;organizations with
1529             *         the name 'Employees' or the city 'Chicago'&quot;.
1530             * @return the number of matching organizations
1531             * @see    com.liferay.portal.service.persistence.OrganizationFinder
1532             */
1533            @Override
1534            public int searchCount(
1535                    long companyId, long parentOrganizationId, String name, String type,
1536                    String street, String city, String zip, Long regionId, Long countryId,
1537                    LinkedHashMap<String, Object> params, boolean andOperator) {
1538    
1539                    if (!PropsValues.ORGANIZATIONS_INDEXER_ENABLED ||
1540                            !PropsValues.ORGANIZATIONS_SEARCH_WITH_INDEX ||
1541                            isUseCustomSQL(params)) {
1542    
1543                            String parentOrganizationIdComparator = StringPool.EQUAL;
1544    
1545                            if (parentOrganizationId ==
1546                                            OrganizationConstants.ANY_PARENT_ORGANIZATION_ID) {
1547    
1548                                    parentOrganizationIdComparator = StringPool.NOT_EQUAL;
1549                            }
1550    
1551                            return organizationFinder.countByC_PO_N_T_S_C_Z_R_C(
1552                                    companyId, parentOrganizationId, parentOrganizationIdComparator,
1553                                    name, type, street, city, zip, regionId, countryId, params,
1554                                    andOperator);
1555                    }
1556    
1557                    try {
1558                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1559                                    Organization.class);
1560    
1561                            SearchContext searchContext = buildSearchContext(
1562                                    companyId, parentOrganizationId, name, type, street, city, zip,
1563                                    regionId, countryId, params, andOperator, QueryUtil.ALL_POS,
1564                                    QueryUtil.ALL_POS, null);
1565    
1566                            Hits hits = indexer.search(searchContext);
1567    
1568                            return hits.getLength();
1569                    }
1570                    catch (Exception e) {
1571                            throw new SystemException(e);
1572                    }
1573            }
1574    
1575            @Override
1576            public BaseModelSearchResult<Organization> searchOrganizations(
1577                            long companyId, long parentOrganizationId, String keywords,
1578                            LinkedHashMap<String, Object> params, int start, int end, Sort sort)
1579                    throws PortalException {
1580    
1581                    String name = null;
1582                    String type = null;
1583                    String street = null;
1584                    String city = null;
1585                    String zip = null;
1586                    String region = null;
1587                    String country = null;
1588                    boolean andOperator = false;
1589    
1590                    if (Validator.isNotNull(keywords)) {
1591                            name = keywords;
1592                            type = keywords;
1593                            street = keywords;
1594                            city = keywords;
1595                            zip = keywords;
1596                            region = keywords;
1597                            country = keywords;
1598                    }
1599                    else {
1600                            andOperator = true;
1601                    }
1602    
1603                    if (params != null) {
1604                            params.put("keywords", keywords);
1605                    }
1606    
1607                    return searchOrganizations(
1608                            companyId, parentOrganizationId, name, type, street, city, zip,
1609                            region, country, params, andOperator, start, end, sort);
1610            }
1611    
1612            @Override
1613            public BaseModelSearchResult<Organization> searchOrganizations(
1614                            long companyId, long parentOrganizationId, String name, String type,
1615                            String street, String city, String zip, String region,
1616                            String country, LinkedHashMap<String, Object> params,
1617                            boolean andSearch, int start, int end, Sort sort)
1618                    throws PortalException {
1619    
1620                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1621                            Organization.class);
1622    
1623                    SearchContext searchContext = buildSearchContext(
1624                            companyId, parentOrganizationId, name, type, street, city, zip,
1625                            region, country, params, andSearch, start, end, sort);
1626    
1627                    for (int i = 0; i < 10; i++) {
1628                            Hits hits = indexer.search(searchContext);
1629    
1630                            List<Organization> organizations = UsersAdminUtil.getOrganizations(
1631                                    hits);
1632    
1633                            if (organizations != null) {
1634                                    return new BaseModelSearchResult<Organization>(
1635                                            organizations, hits.getLength());
1636                            }
1637                    }
1638    
1639                    throw new SearchException(
1640                            "Unable to fix the search index after 10 attempts");
1641            }
1642    
1643            /**
1644             * Sets the organizations in the group, removing and adding organizations to
1645             * the group as necessary.
1646             *
1647             * @param  groupId the primary key of the group
1648             * @param  organizationIds the primary keys of the organizations
1649             * @throws PortalException if a portal exception occurred
1650             */
1651            @Override
1652            public void setGroupOrganizations(long groupId, long[] organizationIds)
1653                    throws PortalException {
1654    
1655                    groupPersistence.setOrganizations(groupId, organizationIds);
1656    
1657                    PermissionCacheUtil.clearCache();
1658            }
1659    
1660            /**
1661             * Removes the organizations from the group.
1662             *
1663             * @param  groupId the primary key of the group
1664             * @param  organizationIds the primary keys of the organizations
1665             * @throws PortalException if a portal exception occurred
1666             */
1667            @Override
1668            public void unsetGroupOrganizations(long groupId, long[] organizationIds)
1669                    throws PortalException {
1670    
1671                    groupPersistence.removeOrganizations(groupId, organizationIds);
1672    
1673                    PermissionCacheUtil.clearCache();
1674            }
1675    
1676            /**
1677             * Removes the organizations from the password policy.
1678             *
1679             * @param passwordPolicyId the primary key of the password policy
1680             * @param organizationIds the primary keys of the organizations
1681             */
1682            @Override
1683            public void unsetPasswordPolicyOrganizations(
1684                    long passwordPolicyId, long[] organizationIds) {
1685    
1686                    passwordPolicyRelLocalService.deletePasswordPolicyRels(
1687                            passwordPolicyId, Organization.class.getName(), organizationIds);
1688            }
1689    
1690            /**
1691             * Updates the organization's asset with the new asset categories and tag
1692             * names, removing and adding asset categories and tag names as necessary.
1693             *
1694             * @param  userId the primary key of the user
1695             * @param  organization the organization
1696             * @param  assetCategoryIds the primary keys of the asset categories
1697             * @param  assetTagNames the asset tag names
1698             * @throws PortalException if a user with the primary key could not be found
1699             */
1700            @Override
1701            public void updateAsset(
1702                            long userId, Organization organization, long[] assetCategoryIds,
1703                            String[] assetTagNames)
1704                    throws PortalException {
1705    
1706                    User user = userPersistence.findByPrimaryKey(userId);
1707    
1708                    Company company = companyPersistence.findByPrimaryKey(
1709                            user.getCompanyId());
1710    
1711                    Group companyGroup = company.getGroup();
1712    
1713                    assetEntryLocalService.updateEntry(
1714                            userId, companyGroup.getGroupId(), null, null,
1715                            Organization.class.getName(), organization.getOrganizationId(),
1716                            organization.getUuid(), 0, assetCategoryIds, assetTagNames, false,
1717                            null, null, null, null, organization.getName(), StringPool.BLANK,
1718                            null, null, null, 0, 0, null, false);
1719            }
1720    
1721            /**
1722             * Updates the organization.
1723             *
1724             * @param      companyId the primary key of the organization's company
1725             * @param      organizationId the primary key of the organization
1726             * @param      parentOrganizationId the primary key of organization's parent
1727             *             organization
1728             * @param      name the organization's name
1729             * @param      type the organization's type
1730             * @param      recursable whether permissions of the organization are to be
1731             *             inherited by its suborganizations
1732             * @param      regionId the primary key of the organization's region
1733             * @param      countryId the primary key of the organization's country
1734             * @param      statusId the organization's workflow status
1735             * @param      comments the comments about the organization
1736             * @param      site whether the organization is to be associated with a main
1737             *             site
1738             * @param      serviceContext the service context to be applied (optionally
1739             *             <code>null</code>). Can set asset category IDs and asset tag
1740             *             names for the organization, and merge expando bridge
1741             *             attributes for the organization.
1742             * @return     the organization
1743             * @throws     PortalException if an organization or parent organization
1744             *             with the primary key could not be found or if the new
1745             *             information was invalid
1746             * @deprecated As of 6.2.0, replaced by {@link #updateOrganization(long,
1747             *             long, long, String, String, long, long, int, String, boolean,
1748             *             byte[], boolean, ServiceContext)}
1749             */
1750            @Deprecated
1751            @Override
1752            public Organization updateOrganization(
1753                            long companyId, long organizationId, long parentOrganizationId,
1754                            String name, String type, boolean recursable, long regionId,
1755                            long countryId, int statusId, String comments, boolean site,
1756                            ServiceContext serviceContext)
1757                    throws PortalException {
1758    
1759                    return updateOrganization(
1760                            companyId, organizationId, parentOrganizationId, name, type,
1761                            regionId, countryId, statusId, comments, true, null, site,
1762                            serviceContext);
1763            }
1764    
1765            /**
1766             * Updates the organization.
1767             *
1768             * @param  companyId the primary key of the organization's company
1769             * @param  organizationId the primary key of the organization
1770             * @param  parentOrganizationId the primary key of organization's parent
1771             *         organization
1772             * @param  name the organization's name
1773             * @param  type the organization's type
1774             * @param  regionId the primary key of the organization's region
1775             * @param  countryId the primary key of the organization's country
1776             * @param  statusId the organization's workflow status
1777             * @param  comments the comments about the organization
1778             * @param  logo whether to update the ogranization's logo
1779             * @param  logoBytes the new logo image data
1780             * @param  site whether the organization is to be associated with a main
1781             *         site
1782             * @param  serviceContext the service context to be applied (optionally
1783             *         <code>null</code>). Can set asset category IDs and asset tag
1784             *         names for the organization, and merge expando bridge attributes
1785             *         for the organization.
1786             * @return the organization
1787             * @throws PortalException if an organization or parent organization with
1788             *         the primary key could not be found or if the new information was
1789             *         invalid
1790             */
1791            @Override
1792            public Organization updateOrganization(
1793                            long companyId, long organizationId, long parentOrganizationId,
1794                            String name, String type, long regionId, long countryId,
1795                            int statusId, String comments, boolean logo, byte[] logoBytes,
1796                            boolean site, ServiceContext serviceContext)
1797                    throws PortalException {
1798    
1799                    // Organization
1800    
1801                    parentOrganizationId = getParentOrganizationId(
1802                            companyId, parentOrganizationId);
1803    
1804                    validate(
1805                            companyId, organizationId, parentOrganizationId, name, type,
1806                            countryId, statusId);
1807    
1808                    Organization organization = organizationPersistence.findByPrimaryKey(
1809                            organizationId);
1810    
1811                    long oldParentOrganizationId = organization.getParentOrganizationId();
1812                    String oldName = organization.getName();
1813    
1814                    organization.setModifiedDate(new Date());
1815                    organization.setParentOrganizationId(parentOrganizationId);
1816                    organization.setTreePath(organization.buildTreePath());
1817                    organization.setName(name);
1818                    organization.setType(type);
1819                    organization.setRecursable(true);
1820                    organization.setRegionId(regionId);
1821                    organization.setCountryId(countryId);
1822                    organization.setStatusId(statusId);
1823                    organization.setComments(comments);
1824    
1825                    PortalUtil.updateImageId(
1826                            organization, logo, logoBytes, "logoId",
1827                            PrefsPropsUtil.getLong(PropsKeys.USERS_IMAGE_MAX_SIZE),
1828                            PropsValues.USERS_IMAGE_MAX_HEIGHT,
1829                            PropsValues.USERS_IMAGE_MAX_WIDTH);
1830    
1831                    organization.setExpandoBridgeAttributes(serviceContext);
1832    
1833                    organizationPersistence.update(organization);
1834    
1835                    // Group
1836    
1837                    Group group = organization.getGroup();
1838    
1839                    long parentGroupId = group.getParentGroupId();
1840    
1841                    boolean createSite = false;
1842    
1843                    if (!group.isSite() && site) {
1844                            createSite = true;
1845                    }
1846    
1847                    boolean organizationGroup = isOrganizationGroup(
1848                            oldParentOrganizationId, group.getParentGroupId());
1849    
1850                    if (createSite || organizationGroup) {
1851                            if (parentOrganizationId !=
1852                                            OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
1853    
1854                                    Organization parentOrganization =
1855                                            organizationPersistence.fetchByPrimaryKey(
1856                                                    parentOrganizationId);
1857    
1858                                    Group parentGroup = parentOrganization.getGroup();
1859    
1860                                    if (site && parentGroup.isSite()) {
1861                                            parentGroupId = parentOrganization.getGroupId();
1862                                    }
1863                                    else {
1864                                            parentGroupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
1865                                    }
1866                            }
1867                            else {
1868                                    parentGroupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
1869                            }
1870                    }
1871    
1872                    if (createSite || !oldName.equals(name) || organizationGroup) {
1873                            groupLocalService.updateGroup(
1874                                    group.getGroupId(), parentGroupId, name, group.getDescription(),
1875                                    group.getType(), group.isManualMembership(),
1876                                    group.getMembershipRestriction(), group.getFriendlyURL(),
1877                                    group.isInheritContent(), group.isActive(), null);
1878                    }
1879    
1880                    if (group.isSite() != site) {
1881                            groupLocalService.updateSite(group.getGroupId(), site);
1882                    }
1883    
1884                    // Organizations
1885    
1886                    if (createSite) {
1887                            List<Organization> childOrganizations =
1888                                    organizationLocalService.getOrganizations(
1889                                            companyId, organizationId);
1890    
1891                            for (Organization childOrganization : childOrganizations) {
1892                                    Group childGroup = childOrganization.getGroup();
1893    
1894                                    if (childGroup.isSite() &&
1895                                            (childGroup.getParentGroupId() ==
1896                                                    GroupConstants.DEFAULT_PARENT_GROUP_ID)) {
1897    
1898                                            childGroup.setParentGroupId(group.getGroupId());
1899    
1900                                            groupLocalService.updateGroup(childGroup);
1901                                    }
1902                            }
1903                    }
1904    
1905                    // Asset
1906    
1907                    if (serviceContext != null) {
1908                            updateAsset(
1909                                    serviceContext.getUserId(), organization,
1910                                    serviceContext.getAssetCategoryIds(),
1911                                    serviceContext.getAssetTagNames());
1912                    }
1913    
1914                    // Indexer
1915    
1916                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1917                            Organization.class);
1918    
1919                    if (oldParentOrganizationId != parentOrganizationId) {
1920                            long[] organizationIds = getReindexOrganizationIds(organization);
1921    
1922                            indexer.reindex(organizationIds);
1923                    }
1924                    else {
1925                            indexer.reindex(organization);
1926                    }
1927    
1928                    return organization;
1929            }
1930    
1931            /**
1932             * Updates the organization.
1933             *
1934             * @param      companyId the primary key of the organization's company
1935             * @param      organizationId the primary key of the organization
1936             * @param      parentOrganizationId the primary key of organization's parent
1937             *             organization
1938             * @param      name the organization's name
1939             * @param      type the organization's type
1940             * @param      regionId the primary key of the organization's region
1941             * @param      countryId the primary key of the organization's country
1942             * @param      statusId the organization's workflow status
1943             * @param      comments the comments about the organization
1944             * @param      site whether the organization is to be associated with a main
1945             *             site
1946             * @param      serviceContext the service context to be applied (optionally
1947             *             <code>null</code>). Can set asset category IDs and asset tag
1948             *             names for the organization, and merge expando bridge
1949             *             attributes for the organization.
1950             * @return     the organization
1951             * @throws     PortalException if an organization or parent organization
1952             *             with the primary key could not be found or if the new
1953             *             information was invalid
1954             * @deprecated As of 7.0.0, replaced by {@link #updateOrganization(long,
1955             *             long, long, String, String, long, long, int, String, boolean,
1956             *             boolean, byte[], ServiceContext)}
1957             */
1958            @Deprecated
1959            @Override
1960            public Organization updateOrganization(
1961                            long companyId, long organizationId, long parentOrganizationId,
1962                            String name, String type, long regionId, long countryId,
1963                            int statusId, String comments, boolean site,
1964                            ServiceContext serviceContext)
1965                    throws PortalException {
1966    
1967                    return updateOrganization(
1968                            companyId, organizationId, parentOrganizationId, name, type,
1969                            regionId, countryId, statusId, comments, site, serviceContext);
1970            }
1971    
1972            protected void addSuborganizations(
1973                    List<Organization> allSuborganizations,
1974                    List<Organization> organizations) {
1975    
1976                    for (Organization organization : organizations) {
1977                            if (!allSuborganizations.contains(organization)) {
1978                                    allSuborganizations.add(organization);
1979    
1980                                    List<Organization> suborganizations =
1981                                            organizationPersistence.findByC_P(
1982                                                    organization.getCompanyId(),
1983                                                    organization.getOrganizationId());
1984    
1985                                    addSuborganizations(allSuborganizations, suborganizations);
1986                            }
1987                    }
1988            }
1989    
1990            protected SearchContext buildSearchContext(
1991                    long companyId, long parentOrganizationId, String name, String type,
1992                    String street, String city, String zip, Long regionId, Long countryId,
1993                    LinkedHashMap<String, Object> params, boolean andSearch, int start,
1994                    int end, Sort sort) {
1995    
1996                    String regionCode = null;
1997    
1998                    if (regionId != null) {
1999                            Region region = regionService.fetchRegion(regionId);
2000    
2001                            regionCode = region.getRegionCode();
2002                    }
2003    
2004                    String countryName = null;
2005    
2006                    if (countryId != null) {
2007                            Country country = countryService.fetchCountry(countryId);
2008    
2009                            countryName = country.getName();
2010                    }
2011    
2012                    return buildSearchContext(
2013                            companyId, parentOrganizationId, name, type, street, city, zip,
2014                            regionCode, countryName, params, andSearch, start, end, sort);
2015            }
2016    
2017            protected SearchContext buildSearchContext(
2018                    long companyId, long parentOrganizationId, String name, String type,
2019                    String street, String city, String zip, String region, String country,
2020                    LinkedHashMap<String, Object> params, boolean andSearch, int start,
2021                    int end, Sort sort) {
2022    
2023                    SearchContext searchContext = new SearchContext();
2024    
2025                    searchContext.setAndSearch(andSearch);
2026    
2027                    Map<String, Serializable> attributes =
2028                            new HashMap<String, Serializable>();
2029    
2030                    attributes.put("city", city);
2031                    attributes.put("country", country);
2032                    attributes.put("name", name);
2033                    attributes.put("params", params);
2034                    attributes.put(
2035                            "parentOrganizationId", String.valueOf(parentOrganizationId));
2036                    attributes.put("region", region);
2037                    attributes.put("street", street);
2038                    attributes.put("type", type);
2039                    attributes.put("zip", zip);
2040    
2041                    searchContext.setAttributes(attributes);
2042    
2043                    searchContext.setCompanyId(companyId);
2044                    searchContext.setEnd(end);
2045    
2046                    if (params != null) {
2047                            String keywords = (String)params.remove("keywords");
2048    
2049                            if (Validator.isNotNull(keywords)) {
2050                                    searchContext.setKeywords(keywords);
2051                            }
2052                    }
2053    
2054                    if (sort != null) {
2055                            searchContext.setSorts(sort);
2056                    }
2057    
2058                    searchContext.setStart(start);
2059    
2060                    QueryConfig queryConfig = searchContext.getQueryConfig();
2061    
2062                    queryConfig.setHighlightEnabled(false);
2063                    queryConfig.setScoreEnabled(false);
2064    
2065                    return searchContext;
2066            }
2067    
2068            protected long getParentOrganizationId(
2069                    long companyId, long parentOrganizationId) {
2070    
2071                    if (parentOrganizationId !=
2072                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
2073    
2074                            // Ensure parent organization exists and belongs to the proper
2075                            // company
2076    
2077                            Organization parentOrganization =
2078                                    organizationPersistence.fetchByPrimaryKey(parentOrganizationId);
2079    
2080                            if ((parentOrganization == null) ||
2081                                    (companyId != parentOrganization.getCompanyId())) {
2082    
2083                                    parentOrganizationId =
2084                                            OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID;
2085                            }
2086                    }
2087    
2088                    return parentOrganizationId;
2089            }
2090    
2091            protected long[] getReindexOrganizationIds(Organization organization)
2092                    throws PortalException {
2093    
2094                    List<Organization> organizations = organizationPersistence.findByC_T(
2095                            organization.getCompanyId(),
2096                            CustomSQLUtil.keywords(organization.getTreePath())[0],
2097                            QueryUtil.ALL_POS, QueryUtil.ALL_POS,
2098                            new OrganizationNameComparator(true));
2099    
2100                    long[] organizationIds = new long[organizations.size()];
2101    
2102                    for (int i = 0; i < organizations.size(); i++) {
2103                            Organization curOrganization = organizations.get(i);
2104    
2105                            curOrganization.setTreePath(curOrganization.buildTreePath());
2106    
2107                            organizationPersistence.update(curOrganization);
2108    
2109                            organizationIds[i] = curOrganization.getOrganizationId();
2110                    }
2111    
2112                    if (!ArrayUtil.contains(
2113                                    organizationIds, organization.getOrganizationId())) {
2114    
2115                            organizationIds = ArrayUtil.append(
2116                                    organizationIds, organization.getOrganizationId());
2117                    }
2118    
2119                    return organizationIds;
2120            }
2121    
2122            protected boolean isOrganizationGroup(long organizationId, long groupId) {
2123                    if ((organizationId ==
2124                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) &&
2125                            (groupId == GroupConstants.DEFAULT_PARENT_GROUP_ID)) {
2126    
2127                            return true;
2128                    }
2129    
2130                    if (organizationId !=
2131                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
2132    
2133                            Organization organization =
2134                                    organizationPersistence.fetchByPrimaryKey(organizationId);
2135    
2136                            if (organization.getGroupId() == groupId) {
2137                                    return true;
2138                            }
2139                    }
2140    
2141                    return false;
2142            }
2143    
2144            protected boolean isParentOrganization(
2145                            long parentOrganizationId, long organizationId)
2146                    throws PortalException {
2147    
2148                    // Return true if parentOrganizationId is among the parent organizatons
2149                    // of organizationId
2150    
2151                    if (organizationId ==
2152                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
2153    
2154                            return false;
2155                    }
2156    
2157                    Organization organization = organizationPersistence.findByPrimaryKey(
2158                            organizationId);
2159    
2160                    String treePath = organization.getTreePath();
2161    
2162                    if (treePath.contains(
2163                                    StringPool.SLASH + parentOrganizationId + StringPool.SLASH)) {
2164    
2165                            return true;
2166                    }
2167                    else {
2168                            return false;
2169                    }
2170            }
2171    
2172            protected boolean isUseCustomSQL(LinkedHashMap<String, Object> params) {
2173                    if (MapUtil.isEmpty(params)) {
2174                            return false;
2175                    }
2176    
2177                    return true;
2178            }
2179    
2180            protected void validate(
2181                            long companyId, long organizationId, long parentOrganizationId,
2182                            String name, String type, long countryId, int statusId)
2183                    throws PortalException {
2184    
2185                    if (!ArrayUtil.contains(PropsValues.ORGANIZATIONS_TYPES, type)) {
2186                            throw new OrganizationTypeException(
2187                                    "Invalid organization type " + type);
2188                    }
2189    
2190                    if (parentOrganizationId ==
2191                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID) {
2192    
2193                            if (!OrganizationImpl.isRootable(type)) {
2194                                    throw new OrganizationParentException(
2195                                            "Organization of type " + type + " cannot be a root");
2196                            }
2197                    }
2198                    else {
2199                            Organization parentOrganization =
2200                                    organizationPersistence.fetchByPrimaryKey(parentOrganizationId);
2201    
2202                            if (parentOrganization == null) {
2203                                    throw new OrganizationParentException(
2204                                            "Organization " + parentOrganizationId + " doesn't exist");
2205                            }
2206    
2207                            String[] childrenTypes = OrganizationImpl.getChildrenTypes(
2208                                    parentOrganization.getType());
2209    
2210                            if (childrenTypes.length == 0) {
2211                                    throw new OrganizationParentException(
2212                                            "Organization of type " + type + " cannot have children");
2213                            }
2214    
2215                            if ((companyId != parentOrganization.getCompanyId()) ||
2216                                    (parentOrganizationId == organizationId)) {
2217    
2218                                    throw new OrganizationParentException();
2219                            }
2220    
2221                            if (!ArrayUtil.contains(childrenTypes, type)) {
2222                                    throw new OrganizationParentException(
2223                                            "Type " + type + " not allowed as child of " +
2224                                                    parentOrganization.getType());
2225                            }
2226                    }
2227    
2228                    if ((organizationId > 0) &&
2229                            (parentOrganizationId !=
2230                                    OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID)) {
2231    
2232                            // Prevent circular organizational references
2233    
2234                            if (isParentOrganization(organizationId, parentOrganizationId)) {
2235                                    throw new OrganizationParentException();
2236                            }
2237                    }
2238    
2239                    if (Validator.isNull(name)) {
2240                            throw new OrganizationNameException();
2241                    }
2242                    else {
2243                            Organization organization = organizationPersistence.fetchByC_N(
2244                                    companyId, name);
2245    
2246                            if ((organization != null) &&
2247                                    StringUtil.equalsIgnoreCase(organization.getName(), name)) {
2248    
2249                                    if ((organizationId <= 0) ||
2250                                            (organization.getOrganizationId() != organizationId)) {
2251    
2252                                            throw new DuplicateOrganizationException(
2253                                                    "There is another organization named " + name);
2254                                    }
2255                            }
2256                    }
2257    
2258                    boolean countryRequired = GetterUtil.getBoolean(
2259                            PropsUtil.get(
2260                                    PropsKeys.ORGANIZATIONS_COUNTRY_REQUIRED, new Filter(type)));
2261    
2262                    if (countryRequired || (countryId > 0)) {
2263                            countryPersistence.findByPrimaryKey(countryId);
2264                    }
2265    
2266                    listTypeService.validate(
2267                            statusId, ListTypeConstants.ORGANIZATION_STATUS);
2268            }
2269    
2270            protected void validate(
2271                            long companyId, long parentOrganizationId, String name, String type,
2272                            long countryId, int statusId)
2273                    throws PortalException {
2274    
2275                    validate(
2276                            companyId, 0, parentOrganizationId, name, type, countryId,
2277                            statusId);
2278            }
2279    
2280    }