org.jboss.weld.probe.Queries Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of weld-servlet-shaded Show documentation
Show all versions of weld-servlet-shaded Show documentation
This jar bundles all the bits of Weld and CDI required for running in a Servlet container.
/*
* JBoss, Home of Professional Open Source
* Copyright 2014, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* 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.jboss.weld.probe;
import static org.jboss.weld.probe.Strings.ADDITIONAL_BDA_SUFFIX;
import static org.jboss.weld.probe.Strings.APPLICATION;
import static org.jboss.weld.probe.Strings.BDA;
import static org.jboss.weld.probe.Strings.BEAN_CLASS;
import static org.jboss.weld.probe.Strings.BEAN_TYPE;
import static org.jboss.weld.probe.Strings.CONTAINER;
import static org.jboss.weld.probe.Strings.DESCRIPTION;
import static org.jboss.weld.probe.Strings.IS_ALTERNATIVE;
import static org.jboss.weld.probe.Strings.KIND;
import static org.jboss.weld.probe.Strings.METHOD_NAME;
import static org.jboss.weld.probe.Strings.OBSERVED_TYPE;
import static org.jboss.weld.probe.Strings.QUALIFIER;
import static org.jboss.weld.probe.Strings.RECEPTION;
import static org.jboss.weld.probe.Strings.SCOPE;
import static org.jboss.weld.probe.Strings.SEARCH;
import static org.jboss.weld.probe.Strings.STEREOTYPES;
import static org.jboss.weld.probe.Strings.TX_PHASE;
import static org.jboss.weld.probe.Strings.UNUSED;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.enterprise.event.Reception;
import javax.enterprise.event.TransactionPhase;
import javax.enterprise.inject.Vetoed;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.ObserverMethod;
import org.jboss.weld.event.ObserverMethodImpl;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.probe.Components.BeanKind;
/**
* A few utility methods and classes to support simple querying (filtering and pagination).
*
* @author Martin Kouba
*/
@Vetoed
final class Queries {
static final int DEFAULT_PAGE_SIZE = 50;
private Queries() {
}
/**
* @param data
* @param page
* @param pageSize
* @param filters
* @return the page of data
*/
static > Page find(List data, int page, int pageSize, F filters) {
if (filters != null && !filters.isEmpty()) {
ProbeLogger.LOG.filtersApplied(filters);
for (Iterator iterator = data.iterator(); iterator.hasNext();) {
T element = iterator.next();
if (!filters.test(element)) {
iterator.remove();
}
}
}
if (pageSize == 0) {
return new Page(page, 1, data.size(), data);
} else {
if (data.isEmpty()) {
return new Page(0, 0, 0, Collections.emptyList());
}
if ((page <= 0) || (page > 1 && (((page - 1) * pageSize) >= data.size()))) {
page = 1;
}
int lastIdx = data.size() / pageSize;
if (data.size() % pageSize > 0) {
lastIdx++;
}
if (lastIdx == 1) {
return new Page(1, lastIdx, data.size(), data);
}
int start = (page - 1) * pageSize;
int end = start + pageSize;
if (end > data.size()) {
end = data.size();
}
return new Page(page, lastIdx, data.size(), data.subList(start, end));
}
}
/**
* A data page abstraction.
*
* @param
* @author Martin Kouba
*/
static class Page {
private final int idx;
private final int lastIdx;
private final int total;
private final List data;
Page(int idx, int lastIdx, int total, List data) {
this.idx = idx;
this.lastIdx = lastIdx;
this.total = total;
this.data = data;
}
int getIdx() {
return idx;
}
int getLastIdx() {
return lastIdx;
}
int getTotal() {
return total;
}
List getData() {
return data;
}
}
static > T initFilters(String filtersParam, T uninitializedFilters) {
if (filtersParam == null || filtersParam.trim().length() == 0) {
return null;
}
uninitializedFilters.initialize(filtersParam);
return uninitializedFilters;
}
/**
* @param
* @author Martin Kouba
*/
abstract static class Filters {
private static final char PAIR_SEPARATOR = ' ';
private static final char KEY_VALUE_SEPARATOR = ':';
private static final char VALUE_QUOTE = '"';
static final String FILTER_ADDITIONAL_BDAS_MARKER = "probe-filterAdditionalBdas";
protected final Probe probe;
static Map parseFilters(String filters) {
List pairs = new ArrayList();
boolean inSeparator = false;
boolean inValueLiteral = false;
StringBuilder buffer = new StringBuilder();
for (int i = 0; i < filters.length(); i++) {
if (filters.charAt(i) == PAIR_SEPARATOR) {
if (!inSeparator) {
if (!inValueLiteral) {
if (buffer.length() > 0) {
pairs.add(buffer.toString());
buffer = new StringBuilder();
}
inSeparator = true;
} else {
buffer.append(filters.charAt(i));
}
}
} else {
if (filters.charAt(i) == VALUE_QUOTE && (i == 0 || filters.charAt(i - 1) == KEY_VALUE_SEPARATOR || i + 1 >= filters.length()
|| filters.charAt(i + 1) == PAIR_SEPARATOR)) {
inValueLiteral = !inValueLiteral;
}
inSeparator = false;
buffer.append(filters.charAt(i));
}
}
if (buffer.length() > 0) {
if (inValueLiteral) {
throw ProbeLogger.LOG.unableToParseQueryFilter(filters);
}
pairs.add(buffer.toString());
}
Map map = new HashMap<>();
for (String pair : pairs) {
if (pair.length() == 0) {
continue;
}
int separator = pair.indexOf(KEY_VALUE_SEPARATOR);
if (separator == -1) {
continue;
}
String key = pair.substring(0, separator);
String value = pair.substring(separator + 1, pair.length());
map.put(key, value.substring(1, value.length() - 1));
}
return map;
}
public Filters(Probe probe) {
this.probe = probe;
}
/**
* Input is a blank-separated list of key-value pairs. Keys and values are separated by {@value #KEY_VALUE_SEPARATOR}. Values must be enclosed in
* quotation marks. E.g. beanClass:"com.foo.Name" scope:"@MyScoped"
.
*
* @param filters
*/
void initialize(String filters) {
for (Entry entry : parseFilters(filters).entrySet()) {
processFilter(entry.getKey(), entry.getValue());
}
}
abstract boolean test(T element);
abstract void processFilter(String name, String value);
/**
* @param filter
* @param value
* @return true if the filter is null or equals to the value
*/
boolean testEquals(Object filter, Object value) {
return filter == null || filter.equals(value);
}
/**
* @param filter
* @param value
* @return true if the filter is null or the value's {@link Object#toString()} contains the filter
*/
boolean testContainsIgnoreCase(String filter, Object value) {
return filter == null || containsIgnoreCase(filter, value);
}
/**
* @param filter
* @param value
* @return true if the filter is null or any of the value's {@link Object#toString()} contains the filter
*/
boolean testAnyContains(String filter, Collection> values) {
if (filter == null) {
return true;
}
for (Object value : values) {
if (testContainsIgnoreCase(filter, value)) {
return true;
}
}
return false;
}
/**
* @param bda
* @param bean
* @return true if the bda is null or the id of the BDA for the given bean equals to the value
*/
boolean testBda(String bda, Bean> bean) {
if (bda == null) {
return true;
}
if (bean == null) {
return false;
}
BeanManagerImpl beanManagerImpl = probe.getBeanManager(bean);
if (beanManagerImpl == null) {
return false;
}
if (FILTER_ADDITIONAL_BDAS_MARKER.equals(bda)) {
if (beanManagerImpl.getId().endsWith(ADDITIONAL_BDA_SUFFIX)) {
return false;
}
} else {
if (!Components.getId(beanManagerImpl.getId()).equals(bda)) {
return false;
}
}
return true;
}
/**
*
* @param filter
* @param value
* @return true if the value's {@link Object#toString()} contains the filter
*/
boolean containsIgnoreCase(String filter, Object value) {
return value.toString().toLowerCase().contains(prepareFilter(filter).toLowerCase());
}
private String prepareFilter(String filter) {
// Expect simplified annotation representation, e.g. @Dependent
return filter.startsWith("@") ? filter.substring(1, filter.length()) : filter;
}
abstract boolean isEmpty();
}
static class BeanFilters extends Filters> {
private BeanKind kind;
private String beanClass;
private String beanType;
private String qualifier;
private String scope;
private String bda;
private Boolean isAlternative;
private String stereotypes;
private boolean unused;
BeanFilters(Probe probe) {
super(probe);
}
BeanFilters(Probe probe, String bda) {
super(probe);
this.bda = bda;
}
@Override
public boolean test(Bean> bean) {
return testBda(bda, bean) && testEquals(kind, BeanKind.from(bean)) && testContainsIgnoreCase(beanClass, bean.getBeanClass())
&& testContainsIgnoreCase(scope, bean.getScope()) && testAnyContains(beanType, bean.getTypes())
&& testAnyContains(qualifier, bean.getQualifiers()) && testEquals(isAlternative, bean.isAlternative())
&& testAnyContains(stereotypes, bean.getStereotypes()) && testUnused(bean);
}
boolean testUnused(Bean> bean) {
return !unused || probe.isUnused(bean);
}
@Override
void processFilter(String name, String value) {
if (KIND.equals(name)) {
kind = BeanKind.from(value);
} else if (BEAN_CLASS.equals(name)) {
beanClass = value;
} else if (BEAN_TYPE.equals(name)) {
beanType = value;
} else if (QUALIFIER.equals(name)) {
qualifier = value;
} else if (SCOPE.equals(name)) {
scope = value;
} else if (BDA.equals(name)) {
bda = value;
} else if (IS_ALTERNATIVE.equals(name)) {
isAlternative = Boolean.valueOf(value);
} else if (STEREOTYPES.equals(name)) {
stereotypes = value;
} else if (UNUSED.equals(name) && Boolean.valueOf(value)) {
unused = true;
}
}
@Override
public String toString() {
return String.format("BeanFilters [kind=%s, beanClass=%s, beanType=%s, qualifier=%s, scope=%s, bda=%s, isAlternative=%s, stereotypes=%s, unused=%s]", kind,
beanClass, beanType, qualifier, scope, bda, isAlternative, stereotypes, unused);
}
@Override
boolean isEmpty() {
return kind == null && beanClass == null && beanType == null && qualifier == null && scope == null && bda == null && isAlternative == null
&& stereotypes == null && !unused;
}
}
static class ObserverFilters extends Filters> {
private String beanClass;
private String observedType;
private String qualifier;
private Reception reception;
private TransactionPhase txPhase;
private BeanKind declaringBeanKind;
private String bda;
ObserverFilters(Probe probe) {
super(probe);
}
ObserverFilters(Probe probe, String observedType, String bda) {
super(probe);
this.observedType = observedType;
this.bda = bda;
}
@Override
boolean test(ObserverMethod> observer) {
final Bean> declaringBean;
if (observer instanceof ObserverMethodImpl) {
declaringBean = ((ObserverMethodImpl, ?>) observer).getDeclaringBean();
} else {
declaringBean = null;
}
return testBda(bda, declaringBean) && testEquals(declaringBeanKind, BeanKind.from(declaringBean)) && testEquals(reception, observer.getReception())
&& testEquals(txPhase, observer.getTransactionPhase()) && testContainsIgnoreCase(beanClass, observer.getBeanClass())
&& testContainsIgnoreCase(observedType, observer.getObservedType()) && testAnyContains(qualifier, observer.getObservedQualifiers());
}
@Override
void processFilter(String name, String value) {
if (KIND.equals(name)) {
declaringBeanKind = BeanKind.from(value);
} else if (BEAN_CLASS.equals(name)) {
beanClass = value;
} else if (OBSERVED_TYPE.equals(name)) {
observedType = value;
} else if (QUALIFIER.equals(name)) {
qualifier = value;
} else if (RECEPTION.equals(name)) {
for (Reception recept : Reception.values()) {
if (recept.toString().equals(value)) {
reception = recept;
}
}
} else if (TX_PHASE.equals(name)) {
for (TransactionPhase phase : TransactionPhase.values()) {
if (phase.toString().equals(value)) {
txPhase = phase;
}
}
} else if (BDA.equals(name)) {
bda = value;
}
}
@Override
public String toString() {
return String.format("ObserverFilters [beanClass=%s, observedType=%s, qualifier=%s, reception=%s, txPhase=%s, declaringBeanKind=%s, bda=%s]",
beanClass, observedType, qualifier, reception, txPhase, declaringBeanKind, bda);
}
@Override
boolean isEmpty() {
return beanClass == null && observedType == null && qualifier == null && reception == null && bda == null && txPhase == null
&& declaringBeanKind == null;
}
}
static class InvocationsFilters extends Filters {
private String beanClass;
private String methodName;
private String search;
private String description;
InvocationsFilters(Probe probe) {
super(probe);
}
@Override
boolean test(Invocation invocation) {
return testSearch(search, invocation) && testContainsIgnoreCase(beanClass, invocation.getBeanClass())
&& testContainsIgnoreCase(methodName, invocation.getMethodName()) && testContainsIgnoreCase(description, invocation.getDescription());
}
@Override
void processFilter(String name, String value) {
if (BEAN_CLASS.equals(name)) {
beanClass = value;
} else if (METHOD_NAME.equals(name)) {
methodName = value;
} else if (SEARCH.equals(name)) {
search = value;
} else if (DESCRIPTION.equals(name)) {
description = value;
}
}
boolean testSearch(String search, Invocation invocation) {
if (search == null) {
return true;
}
if (containsIgnoreCase(search, invocation.getBeanClass()) || containsIgnoreCase(search, invocation.getMethodName())) {
return true;
}
if (invocation.hasChildren()) {
for (Invocation child : invocation.getChildren()) {
if (testSearch(search, child)) {
return true;
}
}
}
return false;
}
@Override
public String toString() {
return String.format("InvocationsFilters [beanClass=%s, methodName=%s, search=%s, description=%s]", beanClass, methodName, search, description);
}
@Override
boolean isEmpty() {
return beanClass == null && methodName == null && search == null && description == null;
}
}
static class EventsFilters extends Filters {
private Boolean container;
private String eventInfo;
private String type;
private String qualifiers;
EventsFilters(Probe probe) {
super(probe);
}
@Override
boolean test(EventInfo event) {
return testContainsIgnoreCase(eventInfo, event.getEventString()) && testContainsIgnoreCase(type, event.getType())
&& testAnyContains(qualifiers, event.getQualifiers()) && (container == null || container == event.isContainerEvent());
}
@Override
void processFilter(String name, String value) {
if (Strings.EVENT_INFO.equals(name)) {
this.eventInfo = value;
} else if (Strings.TYPE.equals(name)) {
this.type = value;
} else if (Strings.QUALIFIERS.equals(name)) {
this.qualifiers = value;
} else if (Strings.KIND.equals(name)) {
if (CONTAINER.equalsIgnoreCase(value)) {
container = true;
} else if (APPLICATION.equalsIgnoreCase(value)) {
container = false;
}
}
}
@Override
public String toString() {
return String.format("EventsFilters [container=%s, eventInfo=%s, type=%s, qualifiers=%s]", container, eventInfo, type, qualifiers);
}
@Override
boolean isEmpty() {
return container == null && eventInfo == null && type == null && qualifiers == null;
}
}
}