/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* licenses this file to you 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 the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>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.apereo.portal.layout.dlm;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apereo.portal.PortalException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* Performs merging of PLF into ILF for DLM.
*
* @since 2.5
*/
public class PLFIntegrator {
private static Log LOG = LogFactory.getLog(PLFIntegrator.class);
public static void mergePLFintoILF(Document plf, Document ilf, IntegrationResult result)
throws PortalException {
// we want to use the root folders located as the single child of
// the layout elements which are the document elements.
Element plfLayout = plf.getDocumentElement();
Element plfRoot = (Element) plfLayout.getFirstChild();
Element ilfLayout = ilf.getDocumentElement();
Element ilfRoot = (Element) ilfLayout.getFirstChild();
DeleteManager.applyAndUpdateDeleteSet(plf, ilf, result);
ParameterEditManager.applyAndUpdateParmEditSet(plf, ilf, result);
if (null == plfRoot) {
throw new RuntimeException(
"The PLF layout root element is missing, so it appears "
+ "that the database has been corrupted.");
}
NodeInfoTracker tracker = new NodeInfoTracker();
applyChildChanges(plfRoot, ilfRoot, result, tracker);
}
private static void applyChildChanges(
Element plfParent, Element ilfParent, IntegrationResult result, NodeInfoTracker tracker)
throws PortalException {
Element positions = null;
Element node = (Element) plfParent.getFirstChild();
while (node != null) {
Element nextNode = (Element) node.getNextSibling();
if (node.getNodeName().equals("folder"))
mergeFolder(node, plfParent, ilfParent, result, tracker);
else if (node.getNodeName().equals(Constants.ELM_POSITION_SET)) positions = node;
else if (node.getNodeName().equals("channel"))
mergeChannel(node, plfParent, ilfParent, result, tracker);
node = nextNode;
}
if (positions != null) {
IntegrationResult posResult = new IntegrationResult();
if (LOG.isInfoEnabled()) LOG.info("applying positions");
PositionManager.applyPositions(ilfParent, positions, posResult, tracker);
if (!posResult.isChangedILF()) {
if (LOG.isInfoEnabled()) LOG.info("removing positionSet");
plfParent.removeChild(positions);
result.setChangedPLF(true);
} else {
result.setChangedILF(true);
if (posResult.isChangedPLF()) result.setChangedPLF(true);
}
}
}
private static void mergeChannel(
Element plfChild,
Element plfParent,
Element ilfParent,
IntegrationResult result,
NodeInfoTracker tracker) {
String id = plfChild.getAttribute(Constants.ATT_ID);
if (id.startsWith(Constants.FRAGMENT_ID_USER_PREFIX)) {
// incorporated channel - if a copy of an inc'd channel is in the
// plf it is because either it has attribute edits. It does not
// imply movement.
// That is accomplished by the position set. So see if it still
// exists in the ilf for applying changes
Document ilf = ilfParent.getOwnerDocument();
Element original = ilf.getElementById(id);
if (original == null) {
// not there anymore, discard from plf
plfParent.removeChild(plfChild);
result.setChangedPLF(true);
return;
}
// found it, apply changes and see if they had any affect
boolean attributeChanged = false;
IntegrationResult childChanges = new IntegrationResult();
attributeChanged = EditManager.applyEditSet(plfChild, original);
applyChildChanges(plfChild, original, childChanges, tracker);
if (attributeChanged == false && !childChanges.isChangedILF()) {
// no changes were used so remove this guy from plf.
plfParent.removeChild(plfChild);
result.setChangedPLF(true);
} else result.setChangedILF(true);
// need to pass on up whether PLF changed in called methods
if (childChanges.isChangedPLF()) result.setChangedPLF(true);
} else // plf channel
{
if (LOG.isInfoEnabled()) LOG.info("merging into ilf channel " + id);
if (ilfParent.getAttribute(Constants.ATT_ADD_CHILD_ALLOWED).equals("false")) {
if (LOG.isInfoEnabled())
LOG.info("removing from plf disallowed add of channel " + id);
plfParent.removeChild(plfChild);
result.setChangedPLF(true);
} else {
appendChild(plfChild, ilfParent, true);
result.setChangedILF(true);
}
}
}
private static void mergeFolder(
Element plfChild,
Element plfParent,
Element ilfParent,
IntegrationResult result,
NodeInfoTracker tracker)
throws PortalException {
String id = plfChild.getAttribute(Constants.ATT_ID);
if (id.startsWith(Constants.FRAGMENT_ID_USER_PREFIX)) {
// incorporated folder - if a copy of an inc'd folder is in the
// plf it is because either it has attribute edits or there are
// nested child changes to be applied. It does not imply movement.
// That is accomplished by the position set. So see if it still
// exists in the ilf for applying changes
Document ilf = ilfParent.getOwnerDocument();
Element original = ilf.getElementById(id);
if (original == null) {
// not there anymore, discard from plf
plfParent.removeChild(plfChild);
result.setChangedPLF(true);
return;
}
// found it, apply changes and see if they had any affect
boolean attributeChanged = false;
IntegrationResult childChanges = new IntegrationResult();
attributeChanged = EditManager.applyEditSet(plfChild, original);
applyChildChanges(plfChild, original, childChanges, tracker);
if (attributeChanged == false && !childChanges.isChangedILF()) {
// no changes were used so remove this guy from plf.
plfParent.removeChild(plfChild);
result.setChangedPLF(true);
} else result.setChangedILF(true);
// need to pass on up whether PLF changed in called methods
if (childChanges.isChangedPLF()) result.setChangedPLF(true);
} else {
// plf folder - the real node. What is being portrayed in this
// case is a plf node that is supposed to be added into the ilf
// parent
if (ilfParent.getAttribute(Constants.ATT_ADD_CHILD_ALLOWED).equals("false")) {
// nope, delete directive from plf
if (LOG.isInfoEnabled()) LOG.info("removing folder from plf " + id);
plfParent.removeChild(plfChild);
result.setChangedPLF(true);
return;
}
Element ilfChild = appendChild(plfChild, ilfParent, false);
result.setChangedILF(true);
IntegrationResult childChanges = new IntegrationResult();
applyChildChanges(plfChild, ilfChild, childChanges, tracker);
if (childChanges.isChangedPLF()) result.setChangedPLF(true);
}
}
/** This method copies a plf node and any of its children into the passed in compViewParent. */
static Element appendChild(Element plfChild, Element parent, boolean copyChildren) {
Document document = parent.getOwnerDocument();
Element copy = (Element) document.importNode(plfChild, false);
parent.appendChild(copy);
// set the identifier for the doc if warrented
String id = copy.getAttribute(Constants.ATT_ID);
if (id != null && !id.equals("")) copy.setIdAttribute(Constants.ATT_ID, true);
if (copyChildren) {
NodeList children = plfChild.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
if (children.item(i) instanceof Element)
appendChild((Element) children.item(i), copy, true);
}
}
return copy;
}
}