/*
* Copyright (C) 2014 GG-Net GmbH - Oliver Günther
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.ggnet.dwoss.customer.eao;
import java.util.*;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.search.Query;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.Search;
import org.hibernate.search.query.dsl.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import eu.ggnet.dwoss.customer.assist.Customers;
import eu.ggnet.dwoss.customer.entity.Communication.Type;
import eu.ggnet.dwoss.rules.CustomerFlag;
import eu.ggnet.dwoss.util.persistence.eao.AbstractEao;
import eu.ggnet.dwoss.customer.entity.*;
import com.mysema.query.jpa.impl.JPAQuery;
import com.mysema.query.types.expr.BooleanExpression;
import lombok.Value;
import static eu.ggnet.dwoss.customer.entity.Communication.Type.EMAIL;
import static eu.ggnet.dwoss.customer.entity.QCommunication.communication;
import static eu.ggnet.dwoss.customer.entity.QCompany.company;
import static eu.ggnet.dwoss.customer.entity.QContact.contact;
import static eu.ggnet.dwoss.customer.entity.QCustomer.customer;
import static org.apache.commons.lang3.StringUtils.isBlank;
/**
* CustomerEao.
* <p>
* @author oliver.guenther
*/
@Stateless
public class CustomerEao extends AbstractEao<Customer> {
/**
* Nice Helper Class, shorter code.
*/
@Value
private static class WildCardHelper {
private final boolean appendWildcard;
public String trim(String s) {
return s.toLowerCase() + (appendWildcard ? "%" : "");
}
}
private final static Logger L = LoggerFactory.getLogger(CustomerEao.class);
private static final Set<String> searchFields = new HashSet<>();
static {;
searchFields.add("comment");
searchFields.add("companies.name");
searchFields.add("companies.contacts.title");
searchFields.add("companies.contacts.firstName");
searchFields.add("companies.contacts.lastName");
searchFields.add("companies.contacts.addresses.street");
searchFields.add("companies.contacts.addresses.city");
searchFields.add("companies.contacts.addresses.zipCode");
searchFields.add("companies.contacts.communications.identifier");
searchFields.add("companies.addresses.street");
searchFields.add("companies.addresses.city");
searchFields.add("companies.addresses.zipCode");
searchFields.add("companies.communications.identifier");
searchFields.add("contacts.title");
searchFields.add("contacts.firstName");
searchFields.add("contacts.lastName");
searchFields.add("contacts.addresses.street");
searchFields.add("contacts.addresses.city");
searchFields.add("contacts.addresses.zipCode");
searchFields.add("contacts.communications.identifier");
}
@Inject
@Customers
private EntityManager em;
public CustomerEao() {
super(Customer.class);
}
public CustomerEao(EntityManager em) {
this();
this.em = em;
}
@Override
public EntityManager getEntityManager() {
return em;
}
/**
* A more specific search based on parameters and possible wildcard handlig.
* All parameters witch are blank will be ignored. The search itself ist like based, so explicit as implicit wildcards are possible
* <p>
* @param companyName the {@link Company#name} of {@link Customer#companies}
* @param firstName the {@link Contact#firstName} of {@link Customer#contacts}
* @param lastName the {@link Contact#lastName} of {@link Customer#contacts}
* @param email the {@link Communication#identifier} with {@link Communication#type} == {@link Type#EMAIL} of {@link Contact#communications} of
* {@link Customer#contacts}
* @param appendWildcard if true, adds a '%' wildcard sign to all set parameters
* @return a list of customers matching the paramters.
*/
public List<Customer> find(String companyName, String firstName, String lastName, String email, boolean appendWildcard) {
WildCardHelper W = new WildCardHelper(appendWildcard);
JPAQuery query = new JPAQuery(em).from(customer);
if ( !isBlank(companyName) ) {
query.join(customer.companies, company).on(company.name.lower().like(W.trim(companyName)));
}
if ( !isBlank(firstName) || !isBlank(lastName) ) {
query.join(customer.contacts, contact).on();
BooleanExpression on = null;
if ( !isBlank(firstName) ) {
on = contact.firstName.lower().like(W.trim(firstName));
}
if ( !isBlank(lastName) ) {
BooleanExpression second = contact.lastName.lower().like(W.trim(lastName));
if ( on != null ) on = on.and(second);
else on = second;
}
query.on(on);
}
if ( !isBlank(email) ) {
query.join(customer.contacts, contact).join(contact.communications, communication)
.on(communication.type.eq(EMAIL).and(communication.identifier.lower().like(W.trim(email))));
}
L.debug("calling query");
List<Customer> list = query.list(customer);
L.debug("Query successful wiht {}", list);
return list;
}
/**
* This Method search for a Customer by his Id or, Company or First- or Lastname.
* First it searchs for the CustomerId when it is possible. If not it search if its 'like' the Company, First- or Lastname.
* <p/>
* @param search
* @return
*/
public List<Customer> find(String search) {
if ( StringUtils.isBlank(search) ) return new ArrayList<>();
search = search.trim();
List<Customer> result = new ArrayList<>();
try {
Long kid = Long.valueOf(search);
Customer find = em.find(Customer.class, kid);
if ( find != null ) result.add(find);
} catch (NumberFormatException numberFormatException) {
// If not a number, ignore.
}
FullTextEntityManager ftem = Search.getFullTextEntityManager(em);
QueryBuilder qb = ftem.getSearchFactory().buildQueryBuilder().forEntity(Customer.class).get();
Query query;
if ( StringUtils.containsWhitespace(search) ) {
// Multiple Words
TermContext keyword = qb.keyword();
TermMatchingContext onField = null;
for (String string : searchFields) {
if ( onField == null ) onField = keyword.onField(string);
else onField = onField.andField(string);
}
query = onField.matching(search.toLowerCase()).createQuery();
} else {
// One Word, wildcards are possibel
WildcardContext keyword = qb.keyword().wildcard();
TermMatchingContext onField = null;
for (String string : searchFields) {
if ( onField == null ) onField = keyword.onField(string);
else onField = onField.andField(string);
}
query = onField.matching(search.toLowerCase()).createQuery();
}
result.addAll(ftem.createFullTextQuery(query, Customer.class).getResultList());
return result;
}
/**
* Returns a list of all System customer Ids.
* <p>
* @return a list of all System customer Ids.
*/
public List<Long> findAllSystemCustomerIds() {
return new JPAQuery(em).from(customer).where(customer.flags.contains(CustomerFlag.SYSTEM_CUSTOMER)).list(customer.id);
}
}