package com.onaro.sanscreen.client.view.tabular; import com.onaro.sanscreen.client.job.QueryJob; import com.onaro.sanscreen.client.view.init.QueryInitInfo; import com.onaro.sanscreen.client.view.selection.SelectedObject; import com.onaro.sanscreen.server.dataobject.Context; import com.onaro.util.InvalidConfigException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.commons.lang3.StringUtils; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; /** * Configuration based factory of {@link QueryJob}s for loading tabular views. A query is a factory producing * {@link QueryJob} according to the configuration. A factory method is used to read an instance of {@link Query} from * the configuration. */ public abstract class Query { static Logger logger = LogManager.getLogger(Query.class); private final Set selectionTypes; public Query() { selectionTypes = new HashSet(); } /** * The factory method that produces a job for loading a table. The details of the job that is produced depends on * the type of query that is configured for the table and on the selection. *

* If no query is needed, no job will be created. * @param selection * the selection that this query is derived from, may be null * @param requestedContext * the job's requested context, may be null * @param currentContext * the context of the response that is already known to the caller, may be null * @param navigationInfo * contains additional parameter that should be included in the request. This parameter may be used by * the query to flag some of the rows. * * @return a job or null if no query is needed */ public abstract QueryJob createJob(SelectedObject selection, Date requestedContext, Context currentContext, NavigationInfo navigationInfo); /** * A factory that creates a query from the configuration. If the configuration contains a single query * element, than an instance of {@link com.onaro.sanscreen.client.view.tabular.Query.SingleQuery} is created. If the * configuration contains multiple query elements inside a single queries element, than it return a * {@link com.onaro.sanscreen.client.view.tabular.Query.QueryList}. * * @return a query */ public static Query createQuery(QueryInitInfo queryInitInfo) { Query query = null; List queryInitInfos = queryInitInfo.getQueries(); if (queryInitInfos ==null || queryInitInfos.isEmpty()) return query; if (queryInitInfos.size() == 1) { query = new SingleQuery(queryInitInfos.get(0)); } else { query = new QueryList(queryInitInfos); } return query; } /** * Configuration based factory of {@link com.onaro.sanscreen.client.job.QueryJob}s of a particular query type and * parameters. */ static class SingleQuery extends Query { /** * The name of the query. Mandatory, read from the "name" attribute. */ private String queryName; /** * The type name of the entity on which the query is issued. Optional, read from the "type" attribute. */ private String entityTypeName; /** * Optoinal, if specified than a query will be issued only if the type of the selection that derives this query * matches this name. It is read from the "selection" attribute. */ private String selectionTypeName; /** * Defines the optional name of the property that holds the id for the query, * If not defined - getId() ("objId") is used */ private String selectionIdPropertyName; /** Optional, if specified then require that an object ID for the selected object be non-null */ private boolean objectIdRequired; private Map queryParams; /** * Reads the specification of the query from the configuration. * * @param confItr * should point to an element providing the name of the query and optionally the type name of the * element that the query refers to and the type name of the selected object derving this query * @throws InvalidConfigException * if the query name wasn't found */ protected SingleQuery(QueryInitInfo.SingleQueryInitInfo singleQueryInitInfo) { queryName = singleQueryInitInfo.getQueryName(); objectIdRequired = singleQueryInitInfo.isObjectIdRequired(); entityTypeName = singleQueryInitInfo.getEntityTypeName(); selectionTypeName = singleQueryInitInfo.getSelectionTypeName(); if (selectionTypeName != null) { getSelectionTypes().add(selectionTypeName); } queryParams = singleQueryInitInfo.getQueryParams(); selectionIdPropertyName = singleQueryInitInfo.getSelectionIdPropertyName(); } /** * Creates a job for issuing a query that loads the table. If no query is needed, no job will be created. * @param selection * optional selection from which to derive the query * @param requestedContext * the job's requested context, may be null * @param currentContext * the time of the response that is already known to the caller, may be null * @param navigationInfo * * @return the job that will perform the qurey or null if no query is needed */ @Override public QueryJob createJob(SelectedObject selection, Date requestedContext, Context currentContext, NavigationInfo navigationInfo) { QueryJob queryJob = null; if (selection == null && selectionTypeName == null) { queryJob = new QueryJob(queryName, entityTypeName, requestedContext, currentContext, navigationInfo); } else if (selection != null) { if (selectionTypeName == null || selectionTypeName.equals(selection.getType())) { Object id = StringUtils.isEmpty(selectionIdPropertyName) ? selection.getId() : selection.getProperty(selectionIdPropertyName); if(!objectIdRequired || id != null) { queryJob = new QueryJob(queryName, entityTypeName, id, requestedContext, currentContext, navigationInfo); } } } if (queryJob != null) { queryJob.addQueryParams(queryParams); } return queryJob; } } /** * A factory of {@link com.onaro.sanscreen.client.job.QueryJob}s that delegates the producing of a job to a list of * {@link Query.SingleQuery}s on a first match basis. */ static class QueryList extends Query { /** * The list of queries. */ private List queries = new LinkedList(); /** * Reads the queries from the configuration and add them to the list. * * @param confItr * should point to an element that contains child 'query' elements * @throws InvalidConfigException * if some attributes were missing */ protected QueryList(List queryInitInfos) { for (QueryInitInfo.SingleQueryInitInfo queryInitInfo : queryInitInfos) { SingleQuery subQuery = new SingleQuery(queryInitInfo); queries.add(subQuery); this.getSelectionTypes().addAll(subQuery.getSelectionTypes()); } } /** * Creates a job by scanning the list of {@link Query.SingleQuery}s, asking them to create a job. The first * query that returns a non null job is selected. * @param selection * optional selection from which to derive the query * @param requestedContext * the job's requested context, may be null * @param currentContext * the time of the response that is already known to the caller, may be null * @param navigationInfo * * @return the job that will perform the qurey or null if no query is needed */ @Override public QueryJob createJob(SelectedObject selection, Date requestedContext, Context currentContext, NavigationInfo navigationInfo) { for (Query query : queries) { QueryJob job = query.createJob(selection, requestedContext, currentContext, navigationInfo); if (job != null) { return job; } } return null; } } public final Set getSelectionTypes() { return selectionTypes; } public final Set getConsumableSelectionTypes(Collection producibleSelectionTypes) { if (producibleSelectionTypes == null) return selectionTypes; Set consumableSelectionTypes = new HashSet(getSelectionTypes()); consumableSelectionTypes.retainAll(producibleSelectionTypes); return consumableSelectionTypes; } }