001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.console.views; 018 019import static org.apache.juneau.commons.utils.Shorts.*; 020 021import java.util.*; 022 023import org.apache.juneau.commons.beanquery.*; 024 025/** 026 * A datatable view definition — an ordered set of {@link Column} definitions carrying each column's search 027 * configuration. This is the bean the {@code VIEW_META} search block is serialized from. 028 * 029 * <p> 030 * A view may also carry a table-level {@link SearchOperatorSet}: it is inherited by every column that 031 * does not supply its own set (see {@link Column#effectiveOperators(SearchOperatorSet)} and 032 * {@link Column#searchMeta(SearchOperatorSet)}). A column that supplies its own set entirely replaces the 033 * table-level set for that column. 034 * 035 * <h5 class='section'>Mutability</h5> 036 * <p> 037 * Deliberately mutable, like {@link Column} and {@link RegionDef}: a {@link ViewDef} is a server-side authoring 038 * bean built up once via fluent setters and {@link #column(Column)} calls while constructing a view, 039 * not an immutable value object. Callers must not mutate one concurrently from more than one 040 * thread, and must not reuse one across requests unless every request treats it as read-only after construction. 041 * 042 * <h5 class='section'>Example:</h5> 043 * <p class='bjava'> 044 * <jc>// A view with a table-level $eq-only default, and one column ("status") that replaces it with $in-only.</jc> 045 * ViewDef <jv>view</jv> = ViewDef.<jsm>create</jsm>(<js>"releases"</js>) 046 * .operators(SearchOperatorSet.<jsm>of</jsm>(SearchOperatorSet.<jsm>standard</jsm>().get(<js>"$eq"</js>))) 047 * .column(Column.<jsm>create</jsm>(<js>"name"</js>).label(<js>"Name"</js>).searchType(SearchType.<jsf>TEXT</jsf>)) 048 * .column(Column.<jsm>create</jsm>(<js>"status"</js>).label(<js>"Status"</js>).searchType(SearchType.<jsf>ID</jsf>) 049 * .operators(SearchOperatorSet.<jsm>of</jsm>(SearchOperatorSet.<jsm>standard</jsm>().get(<js>"$in"</js>)))); 050 * </p> 051 * 052 * <h5 class='section'>See Also:</h5> 053 * <ul> 054 * <li class='jc'>{@link Column} 055 * </ul> 056 * 057 * @since 10.0.0 058 */ 059public final class ViewDef { 060 061 private final String id; 062 private final Map<String,Column> columns = new LinkedHashMap<>(); 063 private SearchOperatorSet operators; 064 065 private ViewDef(String id) { 066 this.id = id; 067 } 068 069 /** 070 * Starts a new view definition. 071 * 072 * @param id The view id (matches the datatable's id on the page). Must not be <jk>null</jk> or blank. 073 * @return A new, empty view definition. 074 * @throws IllegalArgumentException If {@code id} is <jk>null</jk> or blank. 075 */ 076 public static ViewDef create(String id) { 077 req(inb(id), "ViewDef id must not be null or blank."); 078 return new ViewDef(id); 079 } 080 081 /** 082 * Adds a column definition, in order. 083 * 084 * @param value The column. Must not be <jk>null</jk>. 085 * @return This object. 086 * @throws IllegalArgumentException If {@code value} is <jk>null</jk>. 087 */ 088 public ViewDef column(Column value) { 089 req(value != null, "ViewDef '%s' column must not be null.", id); 090 columns.put(value.name(), value); 091 return this; 092 } 093 094 /** 095 * Sets the table-level {@link SearchOperatorSet} — inherited by every column that does not 096 * supply its own set. 097 * 098 * @param value The operator set. Can be <jk>null</jk> to clear it (columns without their own set then fall 099 * back to {@link SearchOperatorSet#standard()}). 100 * @return This object. 101 */ 102 public ViewDef operators(SearchOperatorSet value) { 103 operators = value; 104 return this; 105 } 106 107 /** @return The view id. */ 108 public String id() { 109 return id; 110 } 111 112 /** 113 * The column definitions, in insertion order. 114 * 115 * @return An unmodifiable list of the columns. 116 */ 117 public List<Column> columns() { 118 return List.copyOf(columns.values()); 119 } 120 121 /** 122 * Looks up a column by name. 123 * 124 * @param name The column name. Can be <jk>null</jk>. 125 * @return The column, or <jk>null</jk> if no column has that name. 126 */ 127 public Column findColumn(String name) { 128 return name == null ? null : columns.get(name); 129 } 130 131 /** 132 * This view's table-level operator set, or <jk>null</jk> if absent (columns without their own set fall back to 133 * {@link SearchOperatorSet#standard()}). 134 * 135 * @return The operator set, or <jk>null</jk>. 136 */ 137 public SearchOperatorSet operators() { 138 return operators; 139 } 140}