001    /**
002     * Copyright 2005-2014 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.rice.krad.uif.lifecycle;
017    
018    import java.io.Serializable;
019    import java.util.Collections;
020    import java.util.HashMap;
021    import java.util.List;
022    import java.util.Map;
023    
024    /**
025     * Holds data about a component that might be needed to handle a post request.
026     *
027     * @author Kuali Rice Team (rice.collab@kuali.org)
028     * @see ViewPostMetadata
029     */
030    public class ComponentPostMetadata implements Serializable {
031        private static final long serialVersionUID = -6090575873840392956L;
032    
033        private String id;
034        private String path;
035    
036        private Map<String, String> phasePathMapping;
037        private Map<String, List<String>> refreshPathMappings;
038        private boolean isDetachedComponent;
039    
040        private Map<String, Object> unmodifiableData;
041        private Map<String, Object> data;
042    
043        /**
044         * Constructor taking the id for the component to store metadata for.
045         *
046         * @param id component id
047         */
048        public ComponentPostMetadata(String id) {
049            this.id = id;
050        }
051    
052        /**
053         * Id for the component the post metadata is associated with.
054         *
055         * <p>The id can be used to retrieve the component post metadata from the view post metadata</p>
056         *
057         * @return component id
058         */
059        public String getId() {
060            return id;
061        }
062    
063        /**
064         * @see ComponentPostMetadata#getId()
065         */
066        public void setId(String id) {
067            this.id = id;
068        }
069    
070        /**
071         * Path of the component within the view structure (tree).
072         *
073         * <p>This is set during the lifecycle process and used to retrieve the component for refresh calls</p>
074         *
075         * @return path from view
076         */
077        public String getPath() {
078            return path;
079        }
080    
081        /**
082         * @see ComponentPostMetadata#getPath()
083         */
084        public void setPath(String path) {
085            this.path = path;
086        }
087    
088        /**
089         * Map containing the path for the component at each lifecycle phase.
090         *
091         * <p>Note this is only stored if the path of the component is different from the {@link #getPath()}
092         * at any of the phases</p>
093         *
094         * @return map where key is the phase name and the value is the component's path
095         */
096        public Map<String, String> getPhasePathMapping() {
097            return phasePathMapping;
098        }
099    
100        /**
101         * @see ComponentPostMetadata#getPhasePathMapping()
102         */
103        public void setPhasePathMapping(Map<String, String> phasePathMapping) {
104            this.phasePathMapping = phasePathMapping;
105        }
106    
107        /**
108         * Map of property paths whose lifecycle will be run when the component is refreshed.
109         *
110         * <p>Each map entry contains a tree of paths to process for each of the lifecycle phases. This is so parents
111         * of the component (in each phase) are picked up during the refresh process</p>
112         *
113         * @return map of refresh paths
114         */
115        public Map<String, List<String>> getRefreshPathMappings() {
116            return refreshPathMappings;
117        }
118    
119        /**
120         * @see ComponentPostMetadata#getRefreshPathMappings()
121         */
122        public void setRefreshPathMappings(Map<String, List<String>> refreshPathMappings) {
123            this.refreshPathMappings = refreshPathMappings;
124        }
125    
126        /**
127         * Indicates whether the component is detached from the view (not in the view's structure, but an external
128         * component, for example a dialog).
129         *
130         * <p>This is used by the component refresh process to determine whether it can get the component instance
131         * by its path from the view (in the case of the component being attached), or if it must use its id (in the
132         * case of the component being detached).</p>
133         *
134         * @return boolean true if the component is detached, false if not
135         */
136        public boolean isDetachedComponent() {
137            return isDetachedComponent;
138        }
139    
140        /**
141         * @see ComponentPostMetadata#isDetachedComponent
142         */
143        public void setDetachedComponent(boolean isDetachedComponent) {
144            this.isDetachedComponent = isDetachedComponent;
145        }
146    
147        /**
148         * General post data that has been stored for the component.
149         *
150         * <p>Holds the general post data for a component. Any piece of data can be added to this map and then
151         * retrieved on a post call (for example in a controller method)</p>
152         *
153         * <p>Note map returned is unmodifiable. Use {@link ComponentPostMetadata#addData(java.lang.String,
154         * java.lang.Object)}
155         * to add new data entries</p>
156         *
157         * @return unmodifiable map of data
158         */
159        public Map<String, Object> getData() {
160            if (unmodifiableData == null) {
161                if (data == null) {
162                    unmodifiableData = Collections.emptyMap();
163                } else {
164                    unmodifiableData = Collections.unmodifiableMap(data);
165                }
166            }
167    
168            return unmodifiableData;
169        }
170    
171        /**
172         * @see ComponentPostMetadata#getData()
173         */
174        public void setData(Map<String, Object> data) {
175            this.unmodifiableData = null;
176            this.data = data;
177        }
178    
179        /**
180         * Adds a new data entry to the components post data.
181         *
182         * @param key key for data, which is used to retrieve the data
183         * @param value data value
184         * @see ComponentPostMetadata#getData()
185         */
186        public void addData(String key, Object value) {
187            if (this.data == null) {
188                setData(new HashMap<String, Object>());
189            }
190    
191            if (this.data.get(key) != value) {
192                synchronized (this.data) {
193                    this.data.put(key, value);
194                }
195            }
196        }
197    
198        /**
199         * Retrieves a post data value for the component.
200         *
201         * @param key key for the data value to retrieve
202         * @return data value, or null if data does not exist
203         * @see ComponentPostMetadata#getData()
204         */
205        public Object getData(String key) {
206            if (this.data != null) {
207                return this.data.get(key);
208            }
209    
210            return null;
211        }
212    }