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