View Javadoc
1   /*
2    * Copyright (C) 2015 eXo Platform SAS.
3    *
4    * This is free software; you can redistribute it and/or modify it
5    * under the terms of the GNU Lesser General Public License as
6    * published by the Free Software Foundation; either version 2.1 of
7    * the License, or (at your option) any later version.
8    *
9    * This software is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   * Lesser General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this software; if not, write to the Free
16   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
18   */
19  
20  package org.exoplatform.social.core.jpa.storage.dao.jpa.query;
21  
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.List;
25  
26  import javax.persistence.EntityManager;
27  import javax.persistence.TypedQuery;
28  import javax.persistence.criteria.*;
29  
30  import org.exoplatform.social.core.jpa.search.ExtendProfileFilter;
31  import org.exoplatform.social.core.jpa.storage.entity.IdentityEntity;
32  import org.exoplatform.social.core.jpa.storage.entity.IdentityEntity_;
33  import org.exoplatform.social.core.jpa.storage.entity.ProfileExperienceEntity;
34  import org.exoplatform.social.core.jpa.storage.entity.ProfileExperienceEntity_;
35  import org.exoplatform.social.core.identity.model.Identity;
36  import org.exoplatform.social.core.identity.model.Profile;
37  
38  /**
39   * @author <a href="mailto:tuyennt@exoplatform.com">Tuyen Nguyen The</a>.
40   */
41  public class ProfileQueryBuilder {
42  
43    ExtendProfileFilter filter;
44  
45    private ProfileQueryBuilder() {
46  
47    }
48  
49    public static ProfileQueryBuilder builder() {
50      return new ProfileQueryBuilder();
51    }
52  
53    public ProfileQueryBuilder withFilter(ExtendProfileFilter filter) {
54      this.filter = filter;
55      return this;
56    }
57  
58    /**
59     *
60     * @param em the EntityManager
61     * @return the JPA TypedQuery
62     */
63    public TypedQuery[] build(EntityManager em) {
64      CriteriaBuilder cb = em.getCriteriaBuilder();
65      CriteriaQuery query = cb.createQuery(IdentityEntity.class);
66  
67      Root<IdentityEntity> identity = query.from(IdentityEntity.class);
68  
69      List<Predicate> predicates = new ArrayList<>();
70  
71      if (filter != null) {
72        if (filter.isForceLoadProfile()) {
73          //TODO: profile is now always EAGER load
74  //        Fetch<IdentityEntity,ProfileEntity> fetch = identity.fetch(IdentityEntity_.profile, JoinType.INNER);
75        }
76  
77        if (filter.isExcludeDeleted()) {
78          predicates.add(cb.isFalse(identity.get(IdentityEntity_.deleted)));
79        }
80  
81        if (filter.isExcludeDisabled()) {
82          predicates.add(cb.isTrue(identity.get(IdentityEntity_.enabled)));
83        }
84  
85        if (filter.getIdentityIds() != null && filter.getIdentityIds().size() > 0) {
86          predicates.add(identity.get(IdentityEntity_.id).in(filter.getIdentityIds()));
87        }
88  
89        if (filter.getRemoteIds() != null && filter.getRemoteIds().size() > 0) {
90          predicates.add(identity.get(IdentityEntity_.remoteId).in(filter.getRemoteIds()));
91        }
92  
93        if (filter.getProviderId() != null && !filter.getProviderId().isEmpty()) {
94          predicates.add(cb.equal(identity.get(IdentityEntity_.providerId), filter.getProviderId()));
95        }
96  
97        SetJoin<IdentityEntity, ProfileExperienceEntity> experience = null;
98  
99        List<Identity> excludes = filter.getExcludedIdentityList();
100       if (excludes != null && excludes.size() > 0) {
101         List<Long> ids = new ArrayList<>(excludes.size());
102         for (Identity id : excludes) {
103           ids.add(Long.parseLong(id.getId()));
104         }
105         predicates.add(cb.not(identity.get(IdentityEntity_.id).in(ids)));
106       }
107 
108       String all = filter.getAll();
109       if (all == null || all.trim().isEmpty()) {
110         String name = filter.getName();
111         if (name != null && !name.isEmpty()) {
112           name = processLikeString(name);
113           MapJoin<IdentityEntity, String, String> properties = identity.join(IdentityEntity_.properties, JoinType.LEFT);
114           predicates.add(cb.and(cb.like(cb.lower(properties.value()), name), properties.key().in(Arrays.asList(Profile.FIRST_NAME, Profile.LAST_NAME, Profile.FULL_NAME))));
115         }
116 
117         String val = filter.getPosition();
118         if (val != null && !val.isEmpty()) {
119           val = processLikeString(val);
120           Predicate[] p = new Predicate[2];
121           MapJoin<IdentityEntity, String, String> properties = identity.join(IdentityEntity_.properties, JoinType.LEFT);
122           p[1] = cb.and(cb.like(cb.lower(properties.value()), val), cb.equal(properties.key(), Profile.POSITION));
123           if(experience == null) {
124             experience = identity.join(IdentityEntity_.experiences, JoinType.LEFT);
125           }
126           p[0] = cb.like(cb.lower(experience.get(ProfileExperienceEntity_.position)), val);
127 
128           predicates.add(cb.or(p));
129         }
130 
131         val = filter.getSkills();
132         if (val != null && !val.isEmpty()) {
133           val = processLikeString(val);
134           if(experience == null) {
135             experience = identity.join(IdentityEntity_.experiences, JoinType.LEFT);
136           }
137           predicates.add(cb.like(cb.lower(experience.get(ProfileExperienceEntity_.skills)), val));
138         }
139 
140         val = filter.getCompany();
141         if (val != null && !val.isEmpty()) {
142           val = processLikeString(val);
143           if(experience == null) {
144             experience = identity.join(IdentityEntity_.experiences, JoinType.LEFT);
145           }
146           predicates.add(cb.like(cb.lower(experience.get(ProfileExperienceEntity_.company)), val));
147         }
148       } else {
149 
150         String name = filter.getName();
151         all = processLikeString(all).toLowerCase();
152         Predicate[] p = new Predicate[5];
153         MapJoin<IdentityEntity, String, String> properties = identity.join(IdentityEntity_.properties, JoinType.LEFT);
154         p[0] = cb.and(cb.like(cb.lower(properties.value()), name), properties.key().in(Arrays.asList(Profile.FIRST_NAME, Profile.LAST_NAME, Profile.FULL_NAME)));
155 
156         if(experience == null) {
157           experience = identity.join(IdentityEntity_.experiences, JoinType.LEFT);
158         }
159         p[1] = cb.like(cb.lower(experience.get(ProfileExperienceEntity_.position)), all);
160         p[2] = cb.like(cb.lower(experience.get(ProfileExperienceEntity_.skills)), all);
161         p[3] = cb.like(cb.lower(experience.get(ProfileExperienceEntity_.company)), all);
162         p[4] = cb.like(cb.lower(experience.get(ProfileExperienceEntity_.description)), all);
163 
164         predicates.add(cb.or(p));
165       }
166 
167       char c = filter.getFirstCharacterOfName();
168       if (c != '\u0000') {
169         String val = Character.toLowerCase(c) + "%";
170         MapJoin<IdentityEntity, String, String> properties = identity.join(IdentityEntity_.properties, JoinType.LEFT);
171         predicates.add(cb.and(cb.equal(properties.key(), Profile.LAST_NAME), cb.like(cb.lower(properties.value()), val)));
172       }
173     }
174 
175     Predicate[] pds = predicates.toArray(new Predicate[predicates.size()]);
176 
177     query.select(cb.countDistinct(identity)).where(pds);
178     TypedQuery<Long> count = em.createQuery(query);
179 
180     query.select(identity).distinct(true).where(pds);
181     TypedQuery<IdentityEntity> select = em.createQuery(query);
182 
183 
184     return new TypedQuery[]{select, count};
185   }
186 
187   private String processLikeString(String s) {
188     return "%" + s.toLowerCase() + "%";
189   }
190 }