All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.weld.probe.Queries Maven / Gradle / Ivy

There is a newer version: 3.0.0.Alpha1
Show newest version
/*
 * 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;
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy