001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.workplace.comparison; 029 030import org.opencms.file.CmsFile; 031import org.opencms.file.CmsObject; 032import org.opencms.file.types.CmsResourceTypeXmlPage; 033import org.opencms.main.CmsException; 034import org.opencms.xml.I_CmsXmlDocument; 035import org.opencms.xml.content.CmsXmlContent; 036import org.opencms.xml.content.CmsXmlContentFactory; 037import org.opencms.xml.content.I_CmsXmlContentValueVisitor; 038import org.opencms.xml.page.CmsXmlPageFactory; 039import org.opencms.xml.types.I_CmsXmlContentValue; 040 041import java.util.ArrayList; 042import java.util.Collections; 043import java.util.Iterator; 044import java.util.List; 045import java.util.Locale; 046 047/** 048 * A comparison of properties, attributes and elements of xml documents.<p> 049 */ 050public class CmsXmlDocumentComparison extends CmsResourceComparison { 051 052 /** 053 * Visitor that collects the xpath expressions of xml contents.<p> 054 */ 055 static class CmsXmlContentElementPathExtractor implements I_CmsXmlContentValueVisitor { 056 057 /** The paths to the elements in the xml content. */ 058 private List<CmsElementComparison> m_elementPaths; 059 060 /** 061 * Creates a CmsXmlContentElementPathExtractor.<p> 062 */ 063 CmsXmlContentElementPathExtractor() { 064 065 m_elementPaths = new ArrayList<CmsElementComparison>(); 066 } 067 068 /** 069 * 070 * @see org.opencms.xml.content.I_CmsXmlContentValueVisitor#visit(org.opencms.xml.types.I_CmsXmlContentValue) 071 */ 072 public void visit(I_CmsXmlContentValue value) { 073 074 // only add simple types 075 if (value.isSimpleType()) { 076 m_elementPaths.add( 077 new CmsXmlContentElementComparison(value.getLocale(), value.getPath(), value.getTypeName())); 078 } 079 } 080 081 /** 082 * Returns the elementPaths.<p> 083 * 084 * @return the elementPaths 085 */ 086 List<CmsElementComparison> getElementPaths() { 087 088 return m_elementPaths; 089 } 090 } 091 092 /** The compared elements.<p> */ 093 private List<CmsElementComparison> m_elements; 094 095 /** 096 * Creates a new xml document comparison.<p> 097 * 098 * @param cms the CmsObject to use 099 * @param res1 the first file to compare 100 * @param res2 the second file to compare 101 * 102 * @throws CmsException if something goes wrong 103 */ 104 public CmsXmlDocumentComparison(CmsObject cms, CmsFile res1, CmsFile res2) 105 throws CmsException { 106 107 I_CmsXmlDocument resource1; 108 I_CmsXmlDocument resource2; 109 110 List<CmsElementComparison> elements1 = null; 111 List<CmsElementComparison> elements2 = null; 112 113 if (CmsResourceTypeXmlPage.isXmlPage(res1) && CmsResourceTypeXmlPage.isXmlPage(res2)) { 114 resource1 = CmsXmlPageFactory.unmarshal(cms, res1); 115 resource2 = CmsXmlPageFactory.unmarshal(cms, res2); 116 elements1 = getElements(resource1); 117 elements2 = getElements(resource2); 118 } else { 119 resource1 = CmsXmlContentFactory.unmarshal(cms, res1); 120 CmsXmlContentElementPathExtractor visitor = new CmsXmlContentElementPathExtractor(); 121 ((CmsXmlContent)resource1).visitAllValuesWith(visitor); 122 elements1 = visitor.getElementPaths(); 123 resource2 = CmsXmlContentFactory.unmarshal(cms, res2); 124 visitor = new CmsXmlContentElementPathExtractor(); 125 ((CmsXmlContent)resource2).visitAllValuesWith(visitor); 126 elements2 = visitor.getElementPaths(); 127 } 128 129 List<CmsElementComparison> removed = new ArrayList<CmsElementComparison>(elements1); 130 removed.removeAll(elements2); 131 Iterator<CmsElementComparison> i = removed.iterator(); 132 while (i.hasNext()) { 133 CmsElementComparison elem = i.next(); 134 elem.setStatus(CmsResourceComparison.TYPE_REMOVED); 135 String value = resource1.getValue(elem.getName(), elem.getLocale()).getStringValue(cms); 136 elem.setVersion1(value); 137 elem.setVersion2(""); 138 } 139 List<CmsElementComparison> added = new ArrayList<CmsElementComparison>(elements2); 140 added.removeAll(elements1); 141 i = added.iterator(); 142 while (i.hasNext()) { 143 CmsElementComparison elem = i.next(); 144 elem.setStatus(CmsResourceComparison.TYPE_ADDED); 145 elem.setVersion1(""); 146 I_CmsXmlContentValue contentValue = resource2.getValue(elem.getName(), elem.getLocale()); 147 String value = contentValue.getStringValue(cms); 148 elem.setVersion2(value); 149 } 150 List<CmsElementComparison> union = new ArrayList<CmsElementComparison>(elements1); 151 union.retainAll(elements2); 152 153 // find out, which elements were changed 154 i = new ArrayList<CmsElementComparison>(union).iterator(); 155 while (i.hasNext()) { 156 CmsElementComparison elem = i.next(); 157 String value1 = resource1.getValue(elem.getName(), elem.getLocale()).getStringValue(cms); 158 String value2 = resource2.getValue(elem.getName(), elem.getLocale()).getStringValue(cms); 159 if (value1 == null) { 160 value1 = ""; 161 } 162 if (value2 == null) { 163 value2 = ""; 164 } 165 elem.setVersion1(value1); 166 elem.setVersion2(value2); 167 if (!value1.equals(value2)) { 168 elem.setStatus(CmsResourceComparison.TYPE_CHANGED); 169 } else { 170 elem.setStatus(CmsResourceComparison.TYPE_UNCHANGED); 171 } 172 } 173 m_elements = new ArrayList<CmsElementComparison>(removed); 174 m_elements.addAll(added); 175 m_elements.addAll(union); 176 Collections.sort(m_elements); 177 } 178 179 /** 180 * Returns the elements.<p> 181 * 182 * @return the elements 183 */ 184 public List<CmsElementComparison> getElements() { 185 186 if (m_elements == null) { 187 return Collections.emptyList(); 188 } 189 return Collections.unmodifiableList(m_elements); 190 } 191 192 /** Returs a list of all element names of a xml page.<p> 193 * 194 * @param xmlPage the xml page to read the element names from 195 * @return a list of all element names of a xml page 196 */ 197 private List<CmsElementComparison> getElements(I_CmsXmlDocument xmlPage) { 198 199 List<CmsElementComparison> elements = new ArrayList<CmsElementComparison>(); 200 Iterator<Locale> locales = xmlPage.getLocales().iterator(); 201 while (locales.hasNext()) { 202 Locale locale = locales.next(); 203 Iterator<String> elementNames = xmlPage.getNames(locale).iterator(); 204 while (elementNames.hasNext()) { 205 String elementName = elementNames.next(); 206 elements.add(new CmsElementComparison(locale, elementName)); 207 } 208 } 209 return elements; 210 } 211}