Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2018 Fryske Akademy.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.fryske_akademy.ejb;
/*-
* #%L
* ejbCrudApi
* %%
* Copyright (C) 2018 Fryske Akademy
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.Parameter;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import org.fryske_akademy.ejb.CrudReadService.SORTORDER;
/**
* Stateless, threadsafe builder containing function for building dynamic jpql where and order by clause based
* on {@link Param} and functions for setting parameters in a Query, also based
* on {@link Param}. Supports all comparison expressions except between when
* building jpql.
*
* @author eduard
*/
public class JpqlBuilderImpl implements JpqlBuilder, Serializable {
private static final Logger LOGGER = Logger.getLogger(JpqlBuilder.class.getName());
/**
* tabel alias used in building where and order by clause.
*/
public static final String TABLE_ALIAS = "e";
/**
*
* builds an order by clause, uses {@link #TABLE_ALIAS} as alias for the
* table
*
* @param sort
* @return
*/
@Override
public String orderClause(Map sort) {
if (sort != null && !sort.isEmpty()) {
StringBuilder srt = new StringBuilder("");
boolean first = true;
for (Map.Entry entry : sort.entrySet()) {
String sortField = entry.getKey();
if (sortField == null || entry.getValue() == SORTORDER.NONE) {
continue;
}
srt.append((first) ? " order by" : ",")
.append(" e.").append(sortField).append(" ").append(entry.getValue());
first = false;
}
return srt.toString();
}
return "";
}
/**
* builds a where clause, calls {@link #whereCondition(org.fryske_akademy.ejb.Param)
* }
* for every entry, uses {@link #TABLE_ALIAS} as alias for the table
*
* @param params
* @return
*/
@Override
public String whereClause(List params) {
if (params != null && !params.isEmpty()) {
StringBuilder where = new StringBuilder("");
boolean first = true;
for (Param param : params) {
where.append((first) ? " where" : param.getAndOr()).append(whereCondition(param));
first = false;
}
return where.toString();
}
return "";
}
/**
* builds a where condition, prepares ql parameters later filled in
* {@link #setWhereParams(javax.persistence.Query, java.util.List) }.
* Collection as {@link Param#getParamValue() } with operator "member of"
* supported!, in that case multiple member of conditions will be
* constructed using a parameter key {@link Param#getParamKey() } with an
* index number appended, these parameters and later filled by
* {@link #setParam(javax.persistence.Query, org.fryske_akademy.ejb.Param) }.
* Supports all comparison operators in {@link Param#getOperator() } except
* between, for null and empty comparison {@link Param#getNot() }
* and {@link Param#getParamValue() } are ignored.
*
* @param param
* @return
*/
@Override
public String whereCondition(Param param) {
if (param.getOperator().toLowerCase().contains("member of")) {
if (param.getParamValue() instanceof Collection) {
if (!((Collection) param.getParamValue()).isEmpty()) {
StringBuilder rv = new StringBuilder(" (");
AtomicBoolean first = new AtomicBoolean(true);
AtomicInteger i = new AtomicInteger();
((Collection) param.getParamValue()).forEach((t) -> {
if (first.get()) {
first.set(false);
} else {
rv.append(" or ");
}
rv.append(":").append(param.getParamKey()).append(i.getAndIncrement()).append(param.getNot()).append(param.getOperator()).append(" e.").append(param.getPropertyPath());
});
return rv.append(')').toString();
} else {
throw new PersistenceException("\"member of\" needs a non empty collection");
}
} else {
return " :" + param.getParamKey() + param.getNot() + param.getOperator() + " e." + param.getPropertyPath();
}
} else if (param.getOperator().toLowerCase().contains("in")) {
return " e." + param.getPropertyPath() + param.getNot() + param.getOperator() + "( :" + param.getParamKey() + " )";
} else if (param.getOperator().toLowerCase().contains("null") || param.getOperator().toLowerCase().contains("empty")) {
return " e." + param.getPropertyPath() + param.getOperator();
} else {
return param.getNot() + " e." + param.getPropertyPath() + param.getOperator() + ":" + param.getParamKey();
}
}
/**
* Calls {@link #setParam(javax.persistence.Query, org.fryske_akademy.ejb.Param)
* } for each filter.
*
* @param q
* @param params
*/
@Override
public void setWhereParams(Query q, List params) {
if (params != null && !params.isEmpty()) {
params.forEach((param) -> {
setParam(q, param);
});
}
}
/**
* When Query is a TypedQuery call {@link Query#setParameter(java.lang.String, java.lang.Object) }
* otherwise call {@link Query#setParameter(int, java.lang.Object) } with Short.valueOf(key).
* @param q
* @param key
* @param value
*/
protected void set(Query q, String key, Object value) {
if (q instanceof TypedQuery) {
q.setParameter(key, value);
} else {
q.setParameter(Short.valueOf(key), value);
}
}
/**
* Fills parameters prepared in {@link #setWhereParams(javax.persistence.Query, java.util.List)
* }, if the type of the field in the query is a Short or an Integer and the
* paramValue is a String, it is converted accordingly. For native queries {@link Param#getParamKey() } should
* be a numeric positional parameter.
* When the operator is
* member of and the value is a Collection a value is set for each entry in
* the collection, for this a parameter key {@link Param#getParamKey() }
* with an index number appended is assumed, {@link #whereCondition(org.fryske_akademy.ejb.Param)
* } prepares this. For the type check either
* {@link Parameter#getParameterType() } is used, or, when null, {@link Param#getParamType()
* }. If the query does not contain the parameter and
* {@link Param#isSkipSetValue() } is true, the parameter isn't set. Via
* Param you have full control over the Object that is used as paramValue.
*
* @param q
* @param param
*/
@Override
public void setParam(Query q, Param param) {
boolean hasParam = false;
try {
q.getParameter(param.getParamKey());
hasParam = true;
} catch (IllegalArgumentException | IllegalStateException e) {
}
if (param.isSkipSetValue() && !hasParam) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("skipping " + param);
}
return;
}
if (param.isSkipSetValue() && hasParam) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.warning("Param indicates skipping but query contains it, skipping is ignored: " + param);
}
}
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.fine("trying to set: " + param);
}
Class pt = null;
if (param.getOperator().toLowerCase().contains("member of") && param.getParamValue() instanceof Collection) {
pt = Collection.class;
} else {
try {
pt = q.getParameter(param.getParamKey()).getParameterType() != null ? q.getParameter(param.getParamKey()).getParameterType() : param.getParamType();
} catch (IllegalArgumentException | IllegalStateException e) {
pt = param.getParamType();
}
}
if (Short.class.isAssignableFrom(pt) && param.getParamValue() instanceof String) {
set(q,param.getParamKey(), Short.valueOf(String.valueOf(param.getParamValue())));
} else if (Integer.class.isAssignableFrom(pt) && param.getParamValue() instanceof String) {
set(q,param.getParamKey(), Integer.valueOf(String.valueOf(param.getParamValue())));
} else if (param.getOperator().toLowerCase().contains("member of") && param.getParamValue() instanceof Collection) {
AtomicInteger i = new AtomicInteger();
((Collection) param.getParamValue()).forEach((t) -> {
set(q,param.getParamKey() + (i.getAndIncrement()), t);
});
} else {
if (param.getParamValue() instanceof Collection && !param.getOperator().toLowerCase().contains("in")) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.warning("value for " + param.getParamKey() + " is a collection, you may want to use the \"in\" operator");
}
}
set(q,param.getParamKey(), param.getParamValue());
}
}
}