1 /**
2 * Copyright 2005-2014 The Kuali Foundation
3 *
4 * Licensed under the Educational Community License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.opensource.org/licenses/ecl2.php
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.kuali.rice.krad.uif.lifecycle;
17
18 import java.io.Serializable;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23
24 /**
25 * Holds data about a component that might be needed to handle a post request.
26 *
27 * @author Kuali Rice Team (rice.collab@kuali.org)
28 * @see ViewPostMetadata
29 */
30 public class ComponentPostMetadata implements Serializable {
31
32 private static final long serialVersionUID = -6090575873840392956L;
33
34 private String id;
35 private String path;
36
37 private Map<String, String> phasePathMapping;
38 private Map<String, List<String>> refreshPathMappings;
39 private boolean isDetachedComponent;
40
41 private Map<String, Object> unmodifiableData;
42 private Map<String, Object> data;
43
44 /**
45 * Constructor taking the id for the component to store metadata for.
46 *
47 * @param id component id
48 */
49 public ComponentPostMetadata(String id) {
50 this.id = id;
51 }
52
53 /**
54 * Id for the component the post metadata is associated with.
55 *
56 * <p>The id can be used to retrieve the component post metadata from the view post metadata</p>
57 *
58 * @return component id
59 */
60 public String getId() {
61 return id;
62 }
63
64 /**
65 * @see ComponentPostMetadata#getId()
66 */
67 public void setId(String id) {
68 this.id = id;
69 }
70
71 /**
72 * Path of the component within the view structure (tree).
73 *
74 * <p>This is set during the lifecycle process and used to retrieve the component for refresh calls</p>
75 *
76 * @return path from view
77 */
78 public String getPath() {
79 return path;
80 }
81
82 /**
83 * @see ComponentPostMetadata#getPath()
84 */
85 public void setPath(String path) {
86 this.path = path;
87 }
88
89 /**
90 * Map containing the path for the component at each lifecycle phase.
91 *
92 * <p>Note this is only stored if the path of the component is different from the {@link #getPath()}
93 * at any of the phases</p>
94 *
95 * @return map where key is the phase name and the value is the component's path
96 */
97 public Map<String, String> getPhasePathMapping() {
98 return phasePathMapping;
99 }
100
101 /**
102 * @see ComponentPostMetadata#getPhasePathMapping()
103 */
104 public void setPhasePathMapping(Map<String, String> phasePathMapping) {
105 this.phasePathMapping = phasePathMapping;
106 }
107
108 /**
109 * Map of property paths whose lifecycle will be run when the component is refreshed.
110 *
111 * <p>Each map entry contains a tree of paths to process for each of the lifecycle phases. This is so parents
112 * of the component (in each phase) are picked up during the refresh process</p>
113 *
114 * @return map of refresh paths
115 */
116 public Map<String, List<String>> getRefreshPathMappings() {
117 return refreshPathMappings;
118 }
119
120 /**
121 * @see ComponentPostMetadata#getRefreshPathMappings()
122 */
123 public void setRefreshPathMappings(Map<String, List<String>> refreshPathMappings) {
124 this.refreshPathMappings = refreshPathMappings;
125 }
126
127 /**
128 * Indicates whether the component is detached from the view (not in the view's structure, but an external
129 * component, for example a dialog).
130 *
131 * <p>This is used by the component refresh process to determine whether it can get the component instance
132 * by its path from the view (in the case of the component being attached), or if it must use its id (in the
133 * case of the component being detached).</p>
134 *
135 * @return boolean true if the component is detached, false if not
136 */
137 public boolean isDetachedComponent() {
138 return isDetachedComponent;
139 }
140
141 /**
142 * @see ComponentPostMetadata#isDetachedComponent
143 */
144 public void setDetachedComponent(boolean isDetachedComponent) {
145 this.isDetachedComponent = isDetachedComponent;
146 }
147
148 /**
149 * General post data that has been stored for the component.
150 *
151 * <p>Holds the general post data for a component. Any piece of data can be added to this map and then
152 * retrieved on a post call (for example in a controller method)</p>
153 *
154 * <p>Note map returned is unmodifiable. Use {@link ComponentPostMetadata#addData(java.lang.String,
155 * java.lang.Object)}
156 * to add new data entries</p>
157 *
158 * @return unmodifiable map of data
159 */
160 public Map<String, Object> getData() {
161 if (unmodifiableData == null) {
162 if (data == null) {
163 unmodifiableData = Collections.emptyMap();
164 } else {
165 unmodifiableData = Collections.unmodifiableMap(data);
166 }
167 }
168
169 return unmodifiableData;
170 }
171
172 /**
173 * @see ComponentPostMetadata#getData()
174 */
175 public void setData(Map<String, Object> data) {
176 this.unmodifiableData = null;
177 this.data = data;
178 }
179
180 /**
181 * Adds a new data entry to the components post data.
182 *
183 * @param key key for data, which is used to retrieve the data
184 * @param value data value
185 * @see ComponentPostMetadata#getData()
186 */
187 public void addData(String key, Object value) {
188 if (this.data == null) {
189 setData(new HashMap<String, Object>());
190 }
191
192 if (this.data.get(key) != value) {
193 synchronized (this.data) {
194 this.data.put(key, value);
195 }
196 }
197 }
198
199 /**
200 * Retrieves a post data value for the component.
201 *
202 * @param key key for the data value to retrieve
203 * @return data value, or null if data does not exist
204 *
205 * @see ComponentPostMetadata#getData()
206 */
207 public Object getData(String key) {
208 if (this.data != null) {
209 return this.data.get(key);
210 }
211
212 return null;
213 }
214
215 /**
216 * Get the path of the first object in this components path.
217 *
218 * @return the top most parent object's path for this component
219 */
220 public String getRootObjectPath() {
221 if (this.getPath() == null || !this.getPath().contains(".")) {
222 return this.getPath();
223 }
224
225 return this.getPath().substring(0, this.getPath().indexOf('.'));
226 }
227 }