1/*2 * Licensed to the Apache Software Foundation (ASF) under one3 * or more contributor license agreements. See the NOTICE file4 * distributed with this work for additional information5 * regarding copyright ownership. The ASF licenses this file6 * to you under the Apache License, Version 2.0 (the7 * "License"); you may not use this file except in compliance8 * with the License. You may obtain a copy of the License at9 *10 * http://www.apache.org/licenses/LICENSE-2.011 *12 * Unless required by applicable law or agreed to in writing,13 * software distributed under the License is distributed on an14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY15 * KIND, either express or implied. See the License for the16 * specific language governing permissions and limitations17 * under the License.18 */19package org.apache.myfaces.trinidad.change;
2021import java.util.ArrayList;
22import java.util.Collections;
23import java.util.LinkedHashMap;
24import java.util.List;
25import java.util.Map;
2627import javax.faces.component.UIComponent;
28import org.w3c.dom.Node;
29import org.w3c.dom.NamedNodeMap;
30import org.apache.myfaces.trinidad.logging.TrinidadLogger;
3132/**33 * Change specialization for re-ordering of children.34 * While applying this Change, the specified order of children is restored.35 * @version $Name: $ ($Revision: adfrt/faces/adf-faces-api/src/main/java/oracle/adf/view/faces/change/ReorderChildrenComponentChange.java#0 $) $Date: 10-nov-2005.19:10:01 $36 */37publicclassReorderChildrenComponentChangeextendsComponentChange38implementsDocumentChange39 {
40/**41 * Constructs a ReorderChange with the given List of identifiers for children.42 * @param childIds An in-order collection (List) of Ids (as java.lang.String) 43 * of child components.44 * This List implementation should be of type java.io.Serializable in45 * order to be persisted.46 * If no identifier was passed, it would be assumed that the list 47 * consists of the Ids. 48 * @throws IllegalArgumentException if supplied childIds were to be null.49 */50publicReorderChildrenComponentChange(
51 List<String> childIds
52 )
53 {
54this(childIds, "id");
55 }
5657/**58 * Constructs a ReorderChange with the given List of identifiers for children.59 * @param childIds An in-order collection (List) of Ids (as java.lang.String) 60 * of child components.61 * This List implementation should be of type java.io.Serializable in62 * order to be persisted.63 * @param identifier Determines the type of identifiers which the List consists of.64 * @throws IllegalArgumentException if supplied childIds were to be null or supplied 65 * identifier was to be null or emtpy string.66 */67publicReorderChildrenComponentChange(
68 List<String> childIds,
69 String identifier
70 )
71 {
72if (childIds == null)
73thrownew IllegalArgumentException(_LOG.getMessage(
74"CANNOT_CONSTRUCT_REORDERCHANGE_WITH_NULL_ID"));
7576if (identifier == null || "".equals(identifier))
77thrownew IllegalArgumentException(_LOG.getMessage(
78"IDENTIFIER_TYPE_CANNOT_BE_NULL"));
7980// make serializable copy of list 81 _childIds = Collections.unmodifiableList(new ArrayList<String>(childIds));
8283 _identifier = identifier;
84 }
8586/**87 * Returns an unmodifiable List of the identifiers for the children.88 */89public List<String> getChildIds()
90 {
91return _childIds;
92 }
9394/**95 * Returns the identifier type.96 */97publicfinal String getIdentifier()
98 {
99return _identifier;
100 }
101102/**103 * {@inheritDoc}104 * In case children were to be removed between the time when this Change was105 * added, and the time when it was applied, maybe due to application of a106 * RemoveChildrenChange, such children are not re-instated.107 * In case children were to be added between the time when this Change was108 * added, and the time when it was applied, maybe due to application of an 109 * AddChildChange, such children are appended to the end of the list in110 * preserving the order in which they were added (that is they appear at 111 * the end).112 */113 @SuppressWarnings("unchecked")
114 @Override
115publicvoid changeComponent(UIComponent uiComponent)
116 {
117int childCount = uiComponent.getChildCount();
118if (childCount == 0)
119return;
120121// build order map of of current Nodes, keyed by id122 Map<String, UIComponent> childrenMap = new LinkedHashMap<String, UIComponent>();
123124 List<UIComponent> children = uiComponent.getChildren();
125126int fakeIndex = 0;
127for(UIComponent child : children)
128 {
129 String attrValue = (String)child.getAttributes().get(_identifier);
130131// create a dummy key to maintain order of children whose identifier 132// does not exist133if (attrValue == null)
134 {
135 attrValue = Integer.valueOf(fakeIndex++).toString();
136 }
137 childrenMap.put(attrValue, child);
138 }
139140// remove the children so that we can add them back in141 children.clear();
142143//144// put children back in, in order145//146for(String currReorderID : _childIds)
147 {
148 UIComponent currChild = childrenMap.remove(currReorderID);
149150if (currChild != null)
151 {
152 children.add(currChild);
153 }
154 }
155156// add in all of the rest of the children in157// relative order they originally appeared158 children.addAll(childrenMap.values());
159 }
160161/**162 * {@inheritDoc}163 * In case children were to be removed between the time when this Change was164 * added, and the time when it was applied, maybe due to application of a165 * RemoveChildrenChange, such children are not re-instated.166 * In case children were to be added between the time when this Change was167 * added, and the time when it was applied, maybe due to application of an 168 * AddChildChange, such children are appended to the end of the list in169 * preserving the order in which they were added (that is they appear at 170 * the end).171 */172publicvoid changeDocument(
173 Node componentNode)
174 {
175// build order map of of current Nodes, keyed by id176 LinkedHashMap<String, Node> currChildrenMap = new LinkedHashMap<String, Node>(13);
177178 Node currChild = componentNode.getFirstChild();
179180int fakeIndex = 0;
181while (currChild != null)
182 {
183 NamedNodeMap attributes = currChild.getAttributes();
184185 String currKey = null;
186if (attributes != null)
187 {
188 Node idAttr = attributes.getNamedItem(_identifier);
189190if (idAttr != null)
191 {
192 currKey = idAttr.getNodeValue();
193 }
194 }
195196// create a dummy key to maintain order of non-ided children197if (currKey == null)
198 {
199// =-= bts What about insignificant whitespace?200 currKey = Integer.valueOf(fakeIndex++).toString();
201 }
202203 currChildrenMap.put(currKey, currChild);
204205// remove the children so that we can add them back in206 componentNode.removeChild(currChild);
207208// next node is first node again209 currChild = componentNode.getFirstChild();
210 }
211212//213// put children back in, in order214//215for(String currReorderID : _childIds)
216 {
217 currChild = currChildrenMap.remove(currReorderID);
218if (currChild != null)
219 {
220 componentNode.appendChild(currChild);
221 }
222 }
223224// add in all of the rest of the children in225// relative order they originally appeared226for(Map.Entry<String, Node> entry : currChildrenMap.entrySet())
227 {
228 componentNode.appendChild(entry.getValue());
229 }
230 }
231232/**233 * Returns true if adding the DocumentChange should force the JSP Document234 * to reload235 */236publicboolean getForcesDocumentReload()
237 {
238return false;
239 }
240241privatefinal List<String> _childIds;
242privatefinal String _identifier;
243privatestaticfinalTrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
244 ReorderChildrenComponentChange.class);
245privatestaticfinallong serialVersionUID = 1L;
246 }