View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.trinidad.change;
20  
21  import org.w3c.dom.DocumentFragment;
22  import org.w3c.dom.NamedNodeMap;
23  import org.w3c.dom.Node;
24  import org.apache.myfaces.trinidad.logging.TrinidadLogger;
25  
26  /**
27   * Change specialization for adding a child component using document mark up.
28   * While applying this Change, the child component is created and added to
29   * the document.
30   */
31  public class AddChildDocumentChange extends AddComponentDocumentChange 
32  {
33    /**
34     * Constructs an AddChildDocumentChange with the specified child component 
35     *  mark up.
36     * @param componentFragment DOM mark up for child component to be appended.
37     * @throws IllegalArgumentException if componentFragment is <code>null</code>
38     */
39    public AddChildDocumentChange(DocumentFragment componentFragment)
40    {
41      this(null, componentFragment);
42    }
43    
44    /**
45     * Constructs an AddChildDocumentChange with the specified child component 
46     *  mark up and the identifier of the neighbour. If the neighbour were not to 
47     *  be found while applying this Change, the child is appended to the end of 
48     *  the list of children.
49     * @param insertBeforeId The identifier of the sibling before which this new 
50     *         child is to be inserted or <code>null</code> to append the child
51     * @param componentFragment DOM mark up for child component to be inserted.
52     * @throws IllegalArgumentException if componentFragment is <code>null</code>
53     */
54    public AddChildDocumentChange(
55      String insertBeforeId,
56      DocumentFragment componentFragment)
57    {
58      super(componentFragment);
59      
60      _insertBeforeId = insertBeforeId;
61    }
62    
63    /**
64     * Returns the identifier of the sibling before which this new child needs to
65     *  be inserted.
66     */
67    public String getInsertBeforeId()
68    {
69      return _insertBeforeId;
70    }
71    
72    /**
73     * Given the DOM Node representing a Component, apply any necessary
74     * DOM changes.
75     */
76    public void changeDocument(Node componentNode)
77    {
78      if (componentNode == null)
79        throw new IllegalArgumentException(_LOG.getMessage(
80          "NO_NODE_SPECIFIED"));
81      
82      // get the fragement, imported into the target document
83      DocumentFragment targetFragment = 
84        getImportedComponentFragment(componentNode);
85      
86      // assume that we'll be appending
87      Node insertBeforeNode = null;
88      
89      // search children for the _insertBefore id
90      if (_insertBeforeId != null)
91      {
92        String insertBeforeID = _insertBeforeId;
93        
94        Node currChild = componentNode.getFirstChild();
95        Node idAttr;
96        
97        while (currChild != null)
98        {
99          NamedNodeMap attributes = currChild.getAttributes();
100         
101         if (attributes != null)
102         {
103           idAttr = attributes.getNamedItem("id");
104           if (idAttr != null && insertBeforeID.equals(idAttr.getNodeValue()))
105           {
106             insertBeforeNode = currChild;
107             break;
108           }
109         }
110         currChild = currChild.getNextSibling();
111       }
112     }    
113     
114     // insert our DocumentFragment in the correct position
115     componentNode.insertBefore(targetFragment, insertBeforeNode);
116   }
117   
118   private final String _insertBeforeId;
119   private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
120     AddChildDocumentChange.class);
121 }