edu.unc.lib.dl.util.ContainerContentsHelper.java Source code

Java tutorial

Introduction

Here is the source code for edu.unc.lib.dl.util.ContainerContentsHelper.java

Source

/**
 * Copyright 2008 The University of North Carolina at Chapel Hill
 *
 * 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 edu.unc.lib.dl.util;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.ListIterator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.filter.Filters;

import edu.unc.lib.dl.fedora.PID;
import edu.unc.lib.dl.xml.JDOMNamespaceUtil;

/**
 * A set of functions that are useful for reading, interpreting and writing the container contents XML stream.
 * (MD_CONTENTS)
 * 
 * @author count0
 * 
 */
public class ContainerContentsHelper {
    private static final Log log = LogFactory.getLog(ContainerContentsHelper.class);

    /**
     * Adds new children to the content index. If there is an order specified for a new child, then it will insert the
     * child at the specified position. Any existing children after the specified position will be shifted if neccessary.
     * 
     * @param reordered
     * 
     * @param oldContents
     *           bytes for the old XML CONTENTS stream
     * @param topPid
     *           new child pid
     * @param containerOrder
     * @return
     * @throws JDOMException
     * @throws IOException
     */
    public static Document addChildContentAIPInCustomOrder(Document result, PID containerPID,
            Collection<ContainerPlacement> placements, List<PID> reordered) {
        log.debug("adding child content to MD_CONTENTS XML doc");

        // first build a list of existing pid order in the container
        Element parentDiv = result.getRootElement().getChild("div", JDOMNamespaceUtil.METS_NS);
        List<Element> childDivs = parentDiv.getContent(Filters.element());
        int maxExistingOrder = 5;
        if (childDivs.size() > 0) {
            maxExistingOrder = Integer.parseInt(childDivs.get(childDivs.size() - 1).getAttributeValue("ORDER"));
        }
        ArrayList<PID> order = new ArrayList<PID>(maxExistingOrder + 1);
        try {
            for (Element child : childDivs) {
                int ord = Integer.parseInt(child.getAttributeValue("ORDER"));
                PID pid = new PID(child.getAttributeValue("ID"));
                if (ord >= order.size()) {
                    while (ord > order.size()) { // insert nulls
                        order.add(null);
                    }
                    order.add(pid);
                } else {
                    order.add(ord, pid);
                }
            }
        } catch (NullPointerException e) {
            throw new IllegalRepositoryStateException("Invalid container contents XML (MD_CONTENTS) on: ", e);
        }

        // FIXME: put all the old children in reordered pile, for now
        for (PID p : order) {
            if (p != null) {
                reordered.add(p);
            }
        }

        // clear out the current children
        parentDiv.removeContent();

        // build a list of things with designated order and things with only sip
        // order
        List<ContainerPlacement> designatedOrder = new ArrayList<ContainerPlacement>();
        List<ContainerPlacement> sipOrdered = new ArrayList<ContainerPlacement>();
        List<ContainerPlacement> unordered = new ArrayList<ContainerPlacement>();
        for (ContainerPlacement place : placements) {
            if (containerPID.equals(place.parentPID)) { // only place those objects that go in this container
                if (place.designatedOrder != null) {
                    designatedOrder.add(place);
                } else if (place.sipOrder != null) {
                    sipOrdered.add(place);
                } else {
                    unordered.add(place);
                }
            }
        }
        // order.ensureCapacity(order.size() + designatedOrder.size() +
        // sipOrdered.size());

        // sort designated ordered stuff by that order
        Comparator<ContainerPlacement> designatedSort = new Comparator<ContainerPlacement>() {
            @Override
            public int compare(ContainerPlacement o1, ContainerPlacement o2) {
                if (o1.designatedOrder > o2.designatedOrder) {
                    return 1;
                } else if (o1.designatedOrder < o2.designatedOrder) {
                    return -1;
                }
                return 0;
            }
        };
        // ensure capacity for max of designated and existing, plus count of
        // sipOrdered and a buffer for collisions
        int maxDesignatedOrder = 0;
        if (designatedOrder.size() > 0) {
            Collections.sort(designatedOrder, designatedSort);
            maxDesignatedOrder = designatedOrder.get(designatedOrder.size() - 1).designatedOrder.intValue();
        }
        int capacityEstimate = Math.max(maxDesignatedOrder, maxExistingOrder) + sipOrdered.size() + 10;
        order.ensureCapacity(capacityEstimate);
        // insert the objects with designated order
        for (ContainerPlacement place : designatedOrder) {
            int pos = place.designatedOrder.intValue();
            if (pos >= order.size()) {
                while (pos > order.size()) { // index out of bounds, insert nulls
                    order.add(null);
                }
                order.add(place.pid);
            } else {
                order.add(pos, place.pid);
            }
        }

        // append the objects with sip sibling order
        // sort sip ordered stuff by that order
        Comparator<ContainerPlacement> sipSort = new Comparator<ContainerPlacement>() {
            @Override
            public int compare(ContainerPlacement o1, ContainerPlacement o2) {
                if (o2.sipOrder == null || o1.sipOrder > o2.sipOrder) {
                    return 1;
                } else if (o1.sipOrder == null || o1.sipOrder < o2.sipOrder) {
                    return -1;
                }
                return 0;
            }
        };
        Collections.sort(sipOrdered, sipSort);
        // add SIP ordered
        for (ContainerPlacement place : sipOrdered) {
            order.add(place.pid);
        }
        // add unordered
        for (ContainerPlacement place : unordered) {
            order.add(place.pid);
        }

        for (ListIterator<PID> li = order.listIterator(); li.hasNext();) {
            int ord = li.nextIndex();
            PID pid = li.next();
            if (pid != null) {
                Element el = new Element("div", parentDiv.getNamespace()).setAttribute("ID", pid.getPid())
                        .setAttribute("ORDER", String.valueOf(ord));
                parentDiv.addContent(el);
            }
        }
        return result;
    }

    public static Document remove(Document oldXML, PID pid) {
        Element parentDiv = oldXML.getRootElement().getChild("div", JDOMNamespaceUtil.METS_NS);
        List<Element> childDivs = parentDiv.getChildren();
        Element remove = null;
        for (Element child : childDivs) {
            String p = child.getAttributeValue("ID");
            if (pid.getPid().equals(p)) {
                remove = child;
                break;
            }
        }
        parentDiv.removeContent(remove);
        return oldXML;
    }

    /**
     * @param oldXML
     * @param container
     * @param children
     * @return
     */
    public static Document addChildContentListInCustomOrder(Document oldXML, PID container, List<PID> children,
            Collection<PID> reorderedPids) {
        log.debug("HERE incoming children:");
        for (int i = 0; i < children.size(); i++) {
            log.debug(i + " => " + children.get(i));
        }

        // first build a list of existing pid order in the container
        Element parentDiv = oldXML.getRootElement().getChild("div", JDOMNamespaceUtil.METS_NS);
        List<Element> childDivs = parentDiv.getChildren();
        int maxExistingOrder = 5;
        if (childDivs.size() > 0) {
            maxExistingOrder = Integer.parseInt(childDivs.get(childDivs.size() - 1).getAttributeValue("ORDER"));
        }
        ArrayList<PID> order = new ArrayList<PID>(maxExistingOrder);
        try {
            for (Element child : childDivs) {
                int ord = Integer.parseInt(child.getAttributeValue("ORDER"));
                PID pid = new PID(child.getAttributeValue("ID"));
                if (ord >= order.size()) {
                    while (ord > order.size()) { // insert nulls
                        order.add(null);
                    }
                    order.add(pid);
                } else {
                    order.add(ord, pid);
                }
            }
        } catch (NullPointerException e) {
            throw new IllegalRepositoryStateException("Invalid container contents XML (MD_CONTENTS) on: ", e);
        }

        log.debug("HERE order before merge:");
        for (int i = 0; i < order.size(); i++) {
            log.debug(i + " => " + order.get(i));
        }

        PID[] originalOrder = order.toArray(new PID[0]);

        // clear out the current children
        parentDiv.removeContent();

        int maxIncomingOrder = 0;
        if (children.size() > 0) {
            maxIncomingOrder = children.size() - 1;
        }
        int capacityEstimate = Math.max(maxIncomingOrder, maxExistingOrder) + 10;
        order.ensureCapacity(capacityEstimate);

        for (ListIterator<PID> foo = children.listIterator(); foo.hasNext();) {
            int ord = foo.nextIndex();
            PID child = foo.next();
            if (ord >= order.size()) {
                while (ord > order.size()) { // insert nulls
                    order.add(null);
                }
                order.add(child);
            } else {
                order.add(ord, child);
            }
        }

        log.debug("HERE order after merge:");
        for (int i = 0; i < order.size(); i++) {
            log.debug(i + " => " + order.get(i));
        }

        for (int i = 0; i < originalOrder.length; i++) {
            PID orig = originalOrder[i];
            if (orig != null) {
                if (!orig.equals(order.get(i))) {
                    reorderedPids.add(orig);
                }
            }
        }

        for (ListIterator<PID> li = order.listIterator(); li.hasNext();) {
            int ord = li.nextIndex();
            PID pid = li.next();
            if (pid != null) {
                Element el = new Element("div", parentDiv.getNamespace()).setAttribute("ID", pid.getPid())
                        .setAttribute("ORDER", String.valueOf(ord));
                parentDiv.addContent(el);
            }
        }

        return oldXML;
    }
}