org.apache.syncope.client.console.panels.AbstractSearchPanel.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.syncope.client.console.panels.AbstractSearchPanel.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.syncope.client.console.panels;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.cxf.jaxrs.ext.search.ConditionType;
import org.apache.cxf.jaxrs.ext.search.SearchBean;
import org.apache.cxf.jaxrs.ext.search.SearchCondition;
import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition;
import org.apache.cxf.jaxrs.ext.search.fiql.FiqlParser;
import org.apache.syncope.client.console.rest.AuthRestClient;
import org.apache.syncope.client.console.rest.ResourceRestClient;
import org.apache.syncope.client.console.rest.SchemaRestClient;
import org.apache.syncope.common.lib.search.GroupFiqlSearchConditionBuilder;
import org.apache.syncope.common.lib.search.SearchableFields;
import org.apache.syncope.common.lib.search.SpecialAttr;
import org.apache.syncope.common.lib.search.AbstractFiqlSearchConditionBuilder;
import org.apache.syncope.common.lib.search.SyncopeProperty;
import org.apache.syncope.common.lib.search.UserFiqlSearchConditionBuilder;
import org.apache.syncope.common.lib.to.ResourceTO;
import org.apache.syncope.common.lib.types.AttributableType;
import org.apache.syncope.common.lib.types.SubjectType;
import org.apache.wicket.feedback.FeedbackMessage;
import org.apache.wicket.feedback.IFeedbackMessageFilter;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class AbstractSearchPanel extends Panel {

    private static final long serialVersionUID = 5922413053568696414L;

    /**
     * Logger.
     */
    protected static final Logger LOG = LoggerFactory.getLogger(AbstractSearchPanel.class);

    @SpringBean
    protected SchemaRestClient schemaRestClient;

    @SpringBean
    protected ResourceRestClient resourceRestClient;

    @SpringBean
    protected AuthRestClient authRestClient;

    protected IModel<List<String>> dnames;

    protected IModel<List<String>> anames;

    protected IModel<List<String>> resourceNames;

    protected IModel<List<String>> entitlements;

    protected IModel<List<SearchClause.Type>> types;

    protected IModel<List<String>> groupNames;

    protected NotificationPanel searchFeedback;

    protected List<SearchClause> searchClauses;

    protected WebMarkupContainer searchFormContainer;

    protected AttributableType attributableType;

    protected boolean required;

    protected AbstractSearchPanel(final String id, final AttributableType attributableType) {
        this(id, attributableType, null, true);
    }

    protected AbstractSearchPanel(final String id, final AttributableType attributableType, final String fiql,
            final boolean required) {

        super(id);
        populate();

        this.attributableType = attributableType;
        this.required = required;

        setOutputMarkupId(true);

        searchFormContainer = new WebMarkupContainer("searchFormContainer");
        searchFormContainer.setOutputMarkupId(true);

        searchFeedback = new NotificationPanel("searchFeedback", "notificationpanel_top_right",
                new IFeedbackMessageFilter() {

                    private static final long serialVersionUID = 6895024863321391672L;

                    @Override
                    public boolean accept(final FeedbackMessage message) {
                        boolean result;

                        // messages reported on the session have a null reporter
                        if (message.getReporter() == null) {
                            result = false;
                        } else {
                            // only accept messages coming from the children of the search form container
                            result = searchFormContainer.contains(message.getReporter(), true);
                        }

                        return result;
                    }
                });
        searchFeedback.setOutputMarkupId(true);
        add(searchFeedback);

        this.searchClauses = new ArrayList<>();
        this.searchClauses.add(new SearchClause());
        if (StringUtils.isNotBlank(fiql)) {
            try {
                FiqlParser<SearchBean> fiqlParser = new FiqlParser<>(SearchBean.class,
                        AbstractFiqlSearchConditionBuilder.CONTEXTUAL_PROPERTIES);
                List<SearchClause> parsed = getSearchClauses(fiqlParser.parse(fiql));

                this.searchClauses.clear();
                this.searchClauses.addAll(parsed);
            } catch (Exception e) {
                LOG.error("Unparseable FIQL expression '{}'", fiql, e);
            }
        }

        searchFormContainer.add(new SearchView("searchView", searchClauses, searchFormContainer, required, types,
                anames, dnames, groupNames, resourceNames, entitlements));
        add(searchFormContainer);
    }

    protected void populate() {
        dnames = new LoadableDetachableModel<List<String>>() {

            private static final long serialVersionUID = 5275935387613157437L;

            @Override
            protected List<String> load() {
                return SearchableFields
                        .get(attributableType == AttributableType.USER ? SubjectType.USER : SubjectType.GROUP);
            }
        };

        anames = new LoadableDetachableModel<List<String>>() {

            private static final long serialVersionUID = 5275935387613157437L;

            @Override
            protected List<String> load() {
                return schemaRestClient.getPlainSchemaNames(attributableType);
            }
        };

        resourceNames = new LoadableDetachableModel<List<String>>() {

            private static final long serialVersionUID = 5275935387613157437L;

            @Override
            protected List<String> load() {
                List<ResourceTO> resourceTOs = resourceRestClient.getAll();

                List<String> result = new ArrayList<>(resourceTOs.size());

                for (ResourceTO resource : resourceTOs) {
                    result.add(resource.getKey());
                }

                return result;
            }
        };

        entitlements = new LoadableDetachableModel<List<String>>() {

            private static final long serialVersionUID = 5275935387613157437L;

            @Override
            protected List<String> load() {
                List<String> result = authRestClient.getOwnedEntitlements();
                Collections.sort(result);
                return result;
            }
        };
    }

    public NotificationPanel getSearchFeedback() {
        return searchFeedback;
    }

    private SearchClause getPrimitiveSearchClause(final SearchCondition<SearchBean> sc) {
        SearchClause searchClause = new SearchClause();

        String property = sc.getCondition().getKeySet().iterator().next();
        searchClause.setProperty(property);
        String value = sc.getCondition().get(property);
        searchClause.setValue(value);

        if (SpecialAttr.GROUPS.toString().equals(property)) {
            searchClause.setType(SearchClause.Type.MEMBERSHIP);
            for (String label : groupNames.getObject()) {
                if (value.equals(label.substring(0, label.indexOf(' ')))) {
                    searchClause.setProperty(label);
                }
            }
        } else if (SpecialAttr.RESOURCES.toString().equals(property)) {
            searchClause.setType(SearchClause.Type.RESOURCE);
            searchClause.setProperty(value);
        } else if (SpecialAttr.ENTITLEMENTS.toString().equals(property)) {
            searchClause.setType(SearchClause.Type.ENTITLEMENT);
        } else {
            searchClause.setType(SearchClause.Type.ATTRIBUTE);
        }

        switch (sc.getConditionType()) {
        case EQUALS:
            searchClause.setComparator(SpecialAttr.NULL.toString().equals(value) ? SearchClause.Comparator.IS_NULL
                    : SearchClause.Comparator.EQUALS);
            break;

        case NOT_EQUALS:
            searchClause
                    .setComparator(SpecialAttr.NULL.toString().equals(value) ? SearchClause.Comparator.IS_NOT_NULL
                            : SearchClause.Comparator.NOT_EQUALS);
            break;

        case GREATER_OR_EQUALS:
            searchClause.setComparator(SearchClause.Comparator.GREATER_OR_EQUALS);
            break;

        case GREATER_THAN:
            searchClause.setComparator(SearchClause.Comparator.GREATER_THAN);
            break;

        case LESS_OR_EQUALS:
            searchClause.setComparator(SearchClause.Comparator.LESS_OR_EQUALS);
            break;

        case LESS_THAN:
            searchClause.setComparator(SearchClause.Comparator.LESS_THAN);
            break;

        default:
            break;
        }

        return searchClause;
    }

    private List<SearchClause> getCompoundSearchClause(final SearchCondition<SearchBean> sc) {
        List<SearchClause> clauses = new ArrayList<SearchClause>();

        for (SearchCondition<SearchBean> searchCondition : sc.getSearchConditions()) {
            if (searchCondition.getStatement() == null) {
                clauses.addAll(getCompoundSearchClause(searchCondition));
            } else {
                SearchClause clause = getPrimitiveSearchClause(searchCondition);
                if (sc.getConditionType() == ConditionType.AND) {
                    clause.setOperator(SearchClause.Operator.AND);
                }
                if (sc.getConditionType() == ConditionType.OR) {
                    clause.setOperator(SearchClause.Operator.OR);
                }
                clauses.add(clause);
            }
        }

        return clauses;
    }

    private List<SearchClause> getSearchClauses(final SearchCondition<SearchBean> sc) {
        List<SearchClause> clauses = new ArrayList<SearchClause>();

        if (sc.getStatement() == null) {
            clauses.addAll(getCompoundSearchClause(sc));
        } else {
            clauses.add(getPrimitiveSearchClause(sc));
        }

        return clauses;
    }

    protected abstract AbstractFiqlSearchConditionBuilder getSearchConditionBuilder();

    public String buildFIQL() {
        LOG.debug("Generating FIQL from List<SearchClause>: {}", searchClauses);

        if (searchClauses.isEmpty() || searchClauses.get(0).getType() == null) {
            return StringUtils.EMPTY;
        }

        AbstractFiqlSearchConditionBuilder builder = getSearchConditionBuilder();

        CompleteCondition prevCondition;
        CompleteCondition condition = null;
        for (int i = 0; i < searchClauses.size(); i++) {
            prevCondition = condition;

            switch (searchClauses.get(i).getType()) {
            case ENTITLEMENT:
                condition = searchClauses.get(i).getComparator() == SearchClause.Comparator.EQUALS
                        ? ((GroupFiqlSearchConditionBuilder) builder)
                                .hasEntitlements(searchClauses.get(i).getProperty())
                        : ((GroupFiqlSearchConditionBuilder) builder)
                                .hasNotEntitlements(searchClauses.get(i).getProperty());
                break;

            case MEMBERSHIP:
                Long groupId = NumberUtils.toLong(searchClauses.get(i).getProperty().split(" ")[0]);
                condition = searchClauses.get(i).getComparator() == SearchClause.Comparator.EQUALS
                        ? ((UserFiqlSearchConditionBuilder) builder).inGroups(groupId)
                        : ((UserFiqlSearchConditionBuilder) builder).notInGroups(groupId);
                break;

            case RESOURCE:
                condition = searchClauses.get(i).getComparator() == SearchClause.Comparator.EQUALS
                        ? builder.hasResources(searchClauses.get(i).getProperty())
                        : builder.hasNotResources(searchClauses.get(i).getProperty());
                break;

            case ATTRIBUTE:
                SyncopeProperty property = builder.is(searchClauses.get(i).getProperty());
                switch (searchClauses.get(i).getComparator()) {
                case IS_NULL:
                    condition = builder.isNull(searchClauses.get(i).getProperty());
                    break;

                case IS_NOT_NULL:
                    condition = builder.isNotNull(searchClauses.get(i).getProperty());
                    break;

                case LESS_THAN:
                    condition = StringUtils.isNumeric(searchClauses.get(i).getProperty())
                            ? property.lessThan(NumberUtils.toDouble(searchClauses.get(i).getValue()))
                            : property.lexicalBefore(searchClauses.get(i).getValue());
                    break;

                case LESS_OR_EQUALS:
                    condition = StringUtils.isNumeric(searchClauses.get(i).getProperty())
                            ? property.lessOrEqualTo(NumberUtils.toDouble(searchClauses.get(i).getValue()))
                            : property.lexicalNotAfter(searchClauses.get(i).getValue());
                    break;

                case GREATER_THAN:
                    condition = StringUtils.isNumeric(searchClauses.get(i).getProperty())
                            ? property.greaterThan(NumberUtils.toDouble(searchClauses.get(i).getValue()))
                            : property.lexicalAfter(searchClauses.get(i).getValue());
                    break;

                case GREATER_OR_EQUALS:
                    condition = StringUtils.isNumeric(searchClauses.get(i).getProperty())
                            ? property.greaterOrEqualTo(NumberUtils.toDouble(searchClauses.get(i).getValue()))
                            : property.lexicalNotBefore(searchClauses.get(i).getValue());
                    break;

                case NOT_EQUALS:
                    condition = property.notEqualTo(searchClauses.get(i).getValue());
                    break;

                case EQUALS:
                default:
                    condition = property.equalTo(searchClauses.get(i).getValue());
                    break;
                }
            default:
                break;
            }

            if (i > 0) {
                if (searchClauses.get(i).getOperator() == SearchClause.Operator.AND) {
                    condition = builder.and(prevCondition, condition);
                }
                if (searchClauses.get(i).getOperator() == SearchClause.Operator.OR) {
                    condition = builder.or(prevCondition, condition);
                }
            }
        }

        String fiql = condition == null ? StringUtils.EMPTY : condition.query();
        LOG.debug("Generated FIQL: {}", fiql);
        return fiql;
    }
}