/*
 * Copyright (c) 2006-2012 by Public Library of Science
 * http://plos.org
 * http://ambraproject.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.ambraproject.admin.util;

import com.google.common.base.Preconditions;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.util.AbstractList;
import java.util.List;

/**
 * Adapts a {@link NodeList} to be a {@link List} compatible with the Java Collections Framework.
 */
public class NodeListAdapter extends AbstractList<Node> {

  private final NodeList nodes;

  private NodeListAdapter(NodeList nodes) {
    super();
    this.nodes = Preconditions.checkNotNull(nodes);
  }

  /**
   * Wrap a node list. The returned list is immutable and supports all non-destructive operations.
   *
   * @param nodes a DOM node list
   * @return a Java Collections Framework node list
   * @throws NullPointerException if {@code nodes} is null
   */
  public static List<Node> wrap(NodeList nodes) {
    return new NodeListAdapter(nodes);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public Node get(int index) {
    // To match the List contract (nodes.item returns null on invalid index)
    Preconditions.checkElementIndex(index, size());

    return nodes.item(index);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public int size() {
    return nodes.getLength();
  }

}

@@ -744,16 +744,64 @@
 itions;%0A
+import com.google.common.collect.ImmutableList;%0A
 import o
@@ -1268,13 +1268,16 @@
  is 
-immut
+unmodifi
 able
@@ -1321,16 +1321,213 @@
 rations.
+ Any changes in the%0A   * underlying list will be reflected in this object. (The %7B@link NodeList%7D contract implies, but does not explicitly%0A   * guarantee, that such changes should not be possible.)
 %0A   *%0A  
@@ -1761,32 +1761,443 @@
 er(nodes);%0A  %7D%0A%0A
+  /**%0A   * Make a copy of a node list. The returned list is guaranteed not to change regardless of the original list's%0A   * behavior.%0A   *%0A   * @param nodes a DOM node list%0A   * @return an immutable Java Collections Framework node list%0A   * @throws NullPointerException if %7B@code nodes%7D is null%0A   */%0A  public static ImmutableList%3CNode%3E copy(NodeList nodes) %7B%0A    return ImmutableList.copyOf(wrap(nodes));%0A  %7D%0A%0A
   /**%0A   * %7B@inh
@@ -2384,30 +2384,35 @@
 ze());%0A%0A    
-return
+Node node =
  nodes.item(
@@ -2419,16 +2419,154 @@
 index);%0A
+    if (node == null) %7B%0A      throw new NullPointerException(%22Delegate NodeList returned null for a valid index%22);%0A    %7D%0A    return node;%0A
   %7D%0A%0A  /

Add copy method and check for null elements in NodeListAdapter