/* * This library is part of OpenCms - * the Open Source Content Management System * * Copyright (c) Alkacon Software GmbH (http://www.alkacon.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * For further information about Alkacon Software GmbH, please see the * company website: http://www.alkacon.com * * For further information about OpenCms, please see the * project website: http://www.opencms.org * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.opencms.file; import org.opencms.file.history.I_CmsHistoryResource; import org.opencms.file.types.CmsResourceTypeBinary; import org.opencms.file.types.CmsResourceTypeFolder; import org.opencms.file.types.CmsResourceTypeImage; import org.opencms.file.types.CmsResourceTypeXmlPage; import org.opencms.main.CmsException; import org.opencms.main.OpenCms; import org.opencms.relations.CmsInternalLinksValidator; import org.opencms.relations.CmsRelation; import org.opencms.relations.CmsRelationFilter; import org.opencms.relations.CmsRelationType; import org.opencms.report.CmsShellReport; import org.opencms.test.OpenCmsTestCase; import org.opencms.test.OpenCmsTestProperties; import org.opencms.util.CmsUUID; import org.opencms.xml.content.CmsXmlContent; import org.opencms.xml.content.CmsXmlContentFactory; import org.opencms.xml.page.CmsXmlPage; import org.opencms.xml.page.CmsXmlPageFactory; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import junit.extensions.TestSetup; import junit.framework.Test; import junit.framework.TestSuite; /** * Unit tests for OpenCms link validation.<p> */ public class TestLinkValidation extends OpenCmsTestCase { private static final int MODE_XMLCONTENT_BOTH = 1; private static final int MODE_XMLCONTENT_FILEREF_ONLY = 3; private static final int MODE_XMLCONTENT_HTML_ONLY = 2; private static final int MODE_XMLPAGE = 0; /** * Default JUnit constructor.<p> * * @param arg0 JUnit parameters */ public TestLinkValidation(String arg0) { super(arg0); } /** * Sets the content of a resource.<p> * * @param cms the cms context * @param filename the resource name * @param content the content to set * * @throws CmsException if something goes wrong */ public static void setContent(CmsObject cms, String filename, String content) throws CmsException { CmsResource res = cms.readResource(filename); CmsFile file = cms.readFile(res); CmsXmlPage page = CmsXmlPageFactory.unmarshal(cms, file, true); if (!page.hasValue("test", Locale.ENGLISH)) { page.addValue("test", Locale.ENGLISH); } page.setStringValue(cms, "test", Locale.ENGLISH, content); file.setContents(page.marshal()); cms.lockResource(filename); cms.writeFile(file); } /** * Sets the content of a xmlcontent resource.<p> * * @param cms the cms context * @param filename the resource name * @param html the content to set in the text field * @param link the vfs file reference to set * * @throws CmsException if something goes wrong */ public static void setXmlContent(CmsObject cms, String filename, String html, String link) throws CmsException { CmsResource res = cms.readResource(filename); CmsFile file = cms.readFile(res); CmsXmlContent content = CmsXmlContentFactory.unmarshal(cms, file); if (!content.hasValue("Text", Locale.ENGLISH, 0)) { content.addValue(cms, "Text", Locale.ENGLISH, 0); } content.getValue("Text", Locale.ENGLISH, 0).setStringValue(cms, html); if (!content.hasValue("Homepage", Locale.ENGLISH, 0)) { content.addValue(cms, "Homepage", Locale.ENGLISH, 0); } content.getValue("Homepage", Locale.ENGLISH, 0).setStringValue(cms, link); file.setContents(content.marshal()); cms.lockResource(filename); cms.writeFile(file); } /** * Test suite for this test class.<p> * * @return the test suite */ public static Test suite() { OpenCmsTestProperties.initialize(org.opencms.test.AllTests.TEST_PROPERTIES_PATH); TestSuite suite = new TestSuite(); suite.setName(TestLinkValidation.class.getName()); suite.addTest(new TestLinkValidation("testInternalLinkValidation")); suite.addTest(new TestLinkValidation("testLinkValidationXmlPages")); suite.addTest(new TestLinkValidation("testLinkValidationXmlContents")); suite.addTest(new TestLinkValidation("testLinkValidationXmlContentsHtml")); suite.addTest(new TestLinkValidation("testLinkValidationXmlContentsFileRef")); suite.addTest(new TestLinkValidation("testBrokenLinkFile")); suite.addTest(new TestLinkValidation("testBrokenLinkFolder")); TestSetup wrapper = new TestSetup(suite) { @Override protected void setUp() { setupOpenCms("simpletest", "/"); } @Override protected void tearDown() { removeOpenCms(); } }; return wrapper; } /** * Test internal link validation.<p> * * @throws Throwable if something goes wrong */ public void testInternalLinkValidation() throws Throwable { echo("Testing internal link validation"); CmsObject cms = getCmsObject(); CmsInternalLinksValidator validator = new CmsInternalLinksValidator(cms, Collections.singletonList("/")); assertTrue(validator.getResourcesWithBrokenLinks().isEmpty()); String resName = "testInternalLinkValidation.html"; String linkName = "brokenlink.gif"; CmsResource res = cms.createResource(resName, CmsResourceTypeXmlPage.getStaticTypeId()); setContent(cms, resName, "<img src='" + linkName + "' >"); validator = new CmsInternalLinksValidator(cms, Collections.singletonList("/")); assertEquals(1, validator.getResourcesWithBrokenLinks().size()); assertEquals(res, validator.getResourcesWithBrokenLinks().get(0)); cms.createResource(linkName, CmsResourceTypeBinary.getStaticTypeId()); validator = new CmsInternalLinksValidator(cms, Collections.singletonList("/")); assertTrue(validator.getResourcesWithBrokenLinks().isEmpty()); String linkMoved = "brokenlink2.gif"; cms.moveResource(linkName, linkMoved); validator = new CmsInternalLinksValidator(cms, Collections.singletonList("/")); assertTrue(validator.getResourcesWithBrokenLinks().isEmpty()); cms.deleteResource(linkMoved, CmsResource.DELETE_REMOVE_SIBLINGS); validator = new CmsInternalLinksValidator(cms, Collections.singletonList("/")); assertEquals(1, validator.getResourcesWithBrokenLinks().size()); assertEquals(res, validator.getResourcesWithBrokenLinks().get(0)); } /** * Test broken link issue with files.<p> * * @throws Throwable if something goes wrong */ public void testBrokenLinkFile() throws Throwable { echo("Testing broken link issue with files"); CmsObject cms = getCmsObject(); String resName = "testBrokenLinkFile.html"; String imgName = "testBrokenLinkFile.gif"; CmsResource res = cms.createResource(resName, CmsResourceTypeXmlPage.getStaticTypeId()); List relations = cms.getRelationsForResource(resName, CmsRelationFilter.ALL); assertTrue(relations.isEmpty()); relations = cms.getRelationsForResource(resName, CmsRelationFilter.SOURCES); assertTrue(relations.isEmpty()); relations = cms.getRelationsForResource(resName, CmsRelationFilter.TARGETS); assertTrue(relations.isEmpty()); setContent(cms, resName, "<img src='" + imgName + "' >"); relations = cms.getRelationsForResource(resName, CmsRelationFilter.ALL); assertEquals(1, relations.size()); CmsRelation expected = new CmsRelation( res.getStructureId(), res.getRootPath(), CmsUUID.getNullUUID(), cms.getRequestContext().addSiteRoot(imgName), CmsRelationType.EMBEDDED_IMAGE); assertRelation(expected, (CmsRelation)relations.get(0)); relations = cms.getRelationsForResource(resName, CmsRelationFilter.SOURCES); assertEquals(0, relations.size()); relations = cms.getRelationsForResource(resName, CmsRelationFilter.TARGETS); assertEquals(1, relations.size()); assertRelation(expected, (CmsRelation)relations.get(0)); CmsResource img = cms.createResource(imgName, CmsResourceTypeImage.getStaticTypeId()); relations = cms.getRelationsForResource(resName, CmsRelationFilter.ALL); assertEquals(1, relations.size()); expected = new CmsRelation( res.getStructureId(), res.getRootPath(), img.getStructureId(), img.getRootPath(), CmsRelationType.EMBEDDED_IMAGE); assertRelation(expected, (CmsRelation)relations.get(0)); relations = cms.getRelationsForResource(resName, CmsRelationFilter.SOURCES); assertEquals(0, relations.size()); relations = cms.getRelationsForResource(resName, CmsRelationFilter.TARGETS); assertEquals(1, relations.size()); assertRelation(expected, (CmsRelation)relations.get(0)); } /** * Test broken link issue with folder.<p> * * @throws Throwable if something goes wrong */ public void testBrokenLinkFolder() throws Throwable { echo("Testing broken link issue with folder"); CmsObject cms = getCmsObject(); String resName = "testBrokenLinkFile2.html"; String folderName = "testBrokenLinkFolder/"; String folderName2 = "testBrokenLinkFolder2/"; String imgName = "testBrokenLinkFile2.gif"; // create a new resource CmsResource res = cms.createResource(resName, CmsResourceTypeXmlPage.getStaticTypeId()); // just check that there are no relations after creation List relations = cms.getRelationsForResource(resName, CmsRelationFilter.ALL); assertTrue(relations.isEmpty()); relations = cms.getRelationsForResource(resName, CmsRelationFilter.SOURCES); assertTrue(relations.isEmpty()); relations = cms.getRelationsForResource(resName, CmsRelationFilter.TARGETS); assertTrue(relations.isEmpty()); // set the content to create a relation to an image in a folder setContent(cms, resName, "<img src='" + folderName + imgName + "' >"); // check the new created relation, first as a broken link relations = cms.getRelationsForResource(resName, CmsRelationFilter.ALL); assertEquals(1, relations.size()); CmsRelation expected = new CmsRelation( res.getStructureId(), res.getRootPath(), CmsUUID.getNullUUID(), cms.getRequestContext().addSiteRoot(folderName + imgName), CmsRelationType.EMBEDDED_IMAGE); assertRelation(expected, (CmsRelation)relations.get(0)); relations = cms.getRelationsForResource(resName, CmsRelationFilter.SOURCES); assertEquals(0, relations.size()); relations = cms.getRelationsForResource(resName, CmsRelationFilter.TARGETS); assertEquals(1, relations.size()); assertRelation(expected, (CmsRelation)relations.get(0)); // create an image in a different folder cms.createResource(folderName2, CmsResourceTypeFolder.RESOURCE_TYPE_ID); cms.createResource(folderName2 + imgName, CmsResourceTypeImage.getStaticTypeId()); // just check the relation is still broken relations = cms.getRelationsForResource(resName, CmsRelationFilter.ALL); assertEquals(1, relations.size()); assertRelation(expected, (CmsRelation)relations.get(0)); relations = cms.getRelationsForResource(resName, CmsRelationFilter.SOURCES); assertEquals(0, relations.size()); relations = cms.getRelationsForResource(resName, CmsRelationFilter.TARGETS); assertEquals(1, relations.size()); assertRelation(expected, (CmsRelation)relations.get(0)); // now move the folder so that the image path matches the link cms.moveResource(folderName2, folderName); // check that it is at the right place CmsResource img = cms.readResource(folderName + imgName); // check that the relation is now OK relations = cms.getRelationsForResource(resName, CmsRelationFilter.ALL); assertEquals(1, relations.size()); expected = new CmsRelation( res.getStructureId(), res.getRootPath(), img.getStructureId(), img.getRootPath(), CmsRelationType.EMBEDDED_IMAGE); assertRelation(expected, (CmsRelation)relations.get(0)); relations = cms.getRelationsForResource(resName, CmsRelationFilter.SOURCES); assertEquals(0, relations.size()); relations = cms.getRelationsForResource(resName, CmsRelationFilter.TARGETS); assertEquals(1, relations.size()); assertRelation(expected, (CmsRelation)relations.get(0)); } /** * Test link validation for xml contents with html and file references.<p> * * @throws Throwable if something goes wrong */ public void testLinkValidationXmlContents() throws Throwable { echo("Testing link validation for xml contents with html and file references"); testLinkValidation(MODE_XMLCONTENT_BOTH); } /** * Test link validation for xml contents with only file references.<p> * * @throws Throwable if something goes wrong */ public void testLinkValidationXmlContentsFileRef() throws Throwable { echo("Testing link validation for xml contents with only file references"); testLinkValidation(MODE_XMLCONTENT_FILEREF_ONLY); } /** * Test link validation for xml contents with only html.<p> * * @throws Throwable if something goes wrong */ public void testLinkValidationXmlContentsHtml() throws Throwable { echo("Testing link validation for xml contents with only html"); testLinkValidation(MODE_XMLCONTENT_HTML_ONLY); } /** * Test link validation for xml pages.<p> * * @throws Throwable if something goes wrong */ public void testLinkValidationXmlPages() throws Throwable { echo("Testing link validation for xml pages"); testLinkValidation(MODE_XMLPAGE); } /** * Deletes a resource and publish it.<p> * * @param cms the cms context * @param resName the resource name * @param report the report * * @throws Exception if something goes wrong */ private void delete(CmsObject cms, String resName, CmsShellReport report) throws Exception { cms.lockResource(resName); cms.deleteResource(resName, CmsResource.DELETE_REMOVE_SIBLINGS); cms.unlockResource(resName); OpenCms.getPublishManager().publishResource(cms, resName, true, report); OpenCms.getPublishManager().waitWhileRunning(); } /** * Restores the first version of a resource.<p> * * @param cms the cms context * @param resource the resource * @param report the report * * @throws Exception if something goes wrong */ private void restore(CmsObject cms, CmsResource resource, CmsShellReport report) throws Exception { String resName = cms.getRequestContext().getSitePath(resource); // restore the first historical resource cms.importResource(resName, resource, "import".getBytes(), null); List historicalVersions = cms.readAllAvailableVersions(resName); I_CmsHistoryResource history = (I_CmsHistoryResource)historicalVersions.get(historicalVersions.size() - 1); cms.restoreResourceVersion(history.getStructureId(), history.getVersion()); cms.unlockResource(resName); OpenCms.getPublishManager().publishResource(cms, resName, true, report); OpenCms.getPublishManager().waitWhileRunning(); cms.lockResource(resName); } /** * Sets the content of a xmlcontent resource.<p> * * @param cms the cms context * @param filename the resource name * @param link1 the 1st vfs file reference to set * @param link2 the 2nd vfs file reference to set * * @throws CmsException if something goes wrong */ private void setXmlContentFileRef(CmsObject cms, String filename, String link1, String link2) throws CmsException { CmsResource res = cms.readResource(filename); CmsFile file = cms.readFile(res); CmsXmlContent content = CmsXmlContentFactory.unmarshal(cms, file); if (!content.hasValue("Homepage", Locale.ENGLISH, 0) && (link1 != null)) { content.addValue(cms, "Homepage", Locale.ENGLISH, 0); } if (link1 != null) { content.getValue("Homepage", Locale.ENGLISH, 0).setStringValue(cms, link1); } else { if (content.hasValue("Homepage", Locale.ENGLISH, 0)) { content.removeValue("Homepage", Locale.ENGLISH, 0); } } if (!content.hasValue("Homepage", Locale.ENGLISH, 1) && (link2 != null)) { content.addValue(cms, "Homepage", Locale.ENGLISH, 1); } if (link2 != null) { content.getValue("Homepage", Locale.ENGLISH, 1).setStringValue(cms, link2); } else { if (content.hasValue("Homepage", Locale.ENGLISH, 1)) { content.removeValue("Homepage", Locale.ENGLISH, 1); } } file.setContents(content.marshal()); cms.lockResource(filename); cms.writeFile(file); } /** * Sets the content of a xmlcontent resource.<p> * * @param cms the cms context * @param filename the resource name * @param html the content to set in the text field * * @throws CmsException if something goes wrong */ private void setXmlContentHtml(CmsObject cms, String filename, String html) throws CmsException { CmsResource res = cms.readResource(filename); CmsFile file = cms.readFile(res); CmsXmlContent content = CmsXmlContentFactory.unmarshal(cms, file); if (!content.hasValue("Text", Locale.ENGLISH, 0)) { content.addValue(cms, "Text", Locale.ENGLISH, 0); } content.getValue("Text", Locale.ENGLISH, 0).setStringValue(cms, html); file.setContents(content.marshal()); cms.lockResource(filename); cms.writeFile(file); } /** * Test the link validation for different resource types.<p> * * @param mode the mode: * <code>0</code> for hmlpage, * <code>1</code> for xmlcontent with html and file ref, * <code>2</code> for xmlcontent with html only, * <code>3</code> for xmlcontent with file ref only * * @throws Exception if something goes wrong */ private void testLinkValidation(int mode) throws Exception { CmsObject cms = getCmsObject(); String filename1, filename2, filename3, filename4, filename5, filename6, filename7, filename8; switch (mode) { case MODE_XMLCONTENT_BOTH: filename1 = "/xmlcontent1.html"; filename2 = "/xmlcontent2.html"; filename3 = "/xmlcontent3.html"; filename4 = "/xmlcontent4.html"; filename5 = "/xmlcontent5.html"; filename6 = "/xmlcontent6.html"; filename7 = "/xmlcontent7.html"; filename8 = "/xmlcontent8.html"; break; case MODE_XMLCONTENT_HTML_ONLY: filename1 = "/xmlcontent1html.html"; filename2 = "/xmlcontent2html.html"; filename3 = "/xmlcontent3html.html"; filename4 = "/xmlcontent4html.html"; filename5 = "/xmlcontent5html.html"; filename6 = "/xmlcontent6html.html"; filename7 = "/xmlcontent7html.html"; filename8 = "/xmlcontent8html.html"; break; case MODE_XMLCONTENT_FILEREF_ONLY: filename1 = "/xmlcontent1ref.html"; filename2 = "/xmlcontent2ref.html"; filename3 = "/xmlcontent3ref.html"; filename4 = "/xmlcontent4ref.html"; filename5 = "/xmlcontent5ref.html"; filename6 = "/xmlcontent6ref.html"; filename7 = "/xmlcontent7ref.html"; filename8 = "/xmlcontent8ref.html"; break; default: filename1 = "/xmlpage1.html"; filename2 = "/xmlpage2.html"; filename3 = "/xmlpage3.html"; filename4 = "/xmlpage4.html"; filename5 = "/xmlpage5.html"; filename6 = "/xmlpage6.html"; filename7 = "/xmlpage7.html"; filename8 = "/xmlpage8.html"; break; } // create files int type; if (mode > MODE_XMLPAGE) { type = OpenCmsTestCase.ARTICLE_TYPEID; // article } else { type = CmsResourceTypeXmlPage.getStaticTypeId(); } CmsResource res1 = cms.createResource(filename1, type); CmsResource res2 = cms.createResource(filename2, type); CmsResource res3 = cms.createResource(filename3, type); CmsResource res4 = cms.createResource(filename4, type); CmsResource res5 = cms.createResource(filename5, type); CmsResource res6 = cms.createResource(filename6, type); CmsResource res7 = cms.createResource(filename7, type); // set the content String content1 = "<a href='" + filename2 + "'>file2</a><br><a href='" + filename3 + "'>file3</a>"; String content4 = "<a href='" + filename2 + "'>file2</a>"; String content5 = "<a href='" + filename6 + "'>file6</a>"; String content6 = "<a href='" + filename5 + "'>file5</a>"; CmsRelationType relType1 = null; switch (mode) { case MODE_XMLCONTENT_BOTH: setXmlContent(cms, filename1, content1, filename2); setXmlContent(cms, filename4, content4, filename2); setXmlContent(cms, filename5, content5, filename6); setXmlContent(cms, filename6, content6, filename5); relType1 = CmsRelationType.HYPERLINK; break; case MODE_XMLCONTENT_HTML_ONLY: setXmlContentHtml(cms, filename1, content1); setXmlContentHtml(cms, filename4, content4); setXmlContentHtml(cms, filename5, content5); setXmlContentHtml(cms, filename6, content6); relType1 = CmsRelationType.HYPERLINK; break; case MODE_XMLCONTENT_FILEREF_ONLY: setXmlContentFileRef(cms, filename1, filename2, filename3); setXmlContentFileRef(cms, filename4, filename2, null); setXmlContentFileRef(cms, filename5, filename6, null); setXmlContentFileRef(cms, filename6, filename5, null); relType1 = CmsRelationType.XML_WEAK; break; default: setContent(cms, filename1, content1); setContent(cms, filename4, content4); setContent(cms, filename5, content5); setContent(cms, filename6, content6); relType1 = CmsRelationType.HYPERLINK; break; } // check the links before publishing CmsShellReport report = new CmsShellReport(cms.getRequestContext().getLocale()); cms.unlockProject(cms.getRequestContext().getCurrentProject().getUuid()); Map validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, Collections.singletonList(res1), false), report); assertEquals(validation.size(), 1); assertTrue(validation.keySet().contains(cms.getRequestContext().addSiteRoot(filename1))); List brokenLinks = (List)validation.get(cms.getRequestContext().addSiteRoot(filename1)); assertEquals((mode == MODE_XMLCONTENT_BOTH ? 3 : 2), brokenLinks.size()); assertTrue(brokenLinks.contains(new CmsRelation(res1, res2, relType1))); assertTrue(brokenLinks.contains(new CmsRelation(res1, res3, relType1))); if (mode == MODE_XMLCONTENT_BOTH) { assertTrue(brokenLinks.contains(new CmsRelation(res1, res2, CmsRelationType.XML_WEAK))); } validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, Collections.singletonList(res2), false), report); assertTrue(validation.isEmpty()); validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, Collections.singletonList(res3), false), report); assertTrue(validation.isEmpty()); validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, Collections.singletonList(res4), false), report); assertEquals(validation.size(), 1); assertTrue(validation.keySet().contains(cms.getRequestContext().addSiteRoot(filename4))); brokenLinks = (List)validation.get(cms.getRequestContext().addSiteRoot(filename4)); assertEquals((mode == MODE_XMLCONTENT_BOTH ? 2 : 1), brokenLinks.size()); assertTrue(brokenLinks.contains(new CmsRelation(res4, res2, relType1))); if (mode == MODE_XMLCONTENT_BOTH) { assertTrue(brokenLinks.contains(new CmsRelation(res4, res2, CmsRelationType.XML_WEAK))); } validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, Collections.singletonList(res5), false), report); assertEquals(validation.size(), 1); assertTrue(validation.keySet().contains(cms.getRequestContext().addSiteRoot(filename5))); brokenLinks = (List)validation.get(cms.getRequestContext().addSiteRoot(filename5)); assertEquals(brokenLinks.size(), (mode == MODE_XMLCONTENT_BOTH ? 2 : 1)); assertTrue(brokenLinks.contains(new CmsRelation(res5, res6, relType1))); if (mode == MODE_XMLCONTENT_BOTH) { assertTrue(brokenLinks.contains(new CmsRelation(res5, res6, CmsRelationType.XML_WEAK))); } validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, Collections.singletonList(res6), false), report); assertEquals(validation.size(), 1); assertTrue(validation.keySet().contains(cms.getRequestContext().addSiteRoot(filename6))); brokenLinks = (List)validation.get(cms.getRequestContext().addSiteRoot(filename6)); assertEquals(brokenLinks.size(), (mode == MODE_XMLCONTENT_BOTH ? 2 : 1)); assertTrue(brokenLinks.contains(new CmsRelation(res6, res5, relType1))); if (mode == MODE_XMLCONTENT_BOTH) { assertTrue(brokenLinks.contains(new CmsRelation(res6, res5, CmsRelationType.XML_WEAK))); } validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, Collections.singletonList(res7), false), report); assertTrue(validation.isEmpty()); List res56 = new ArrayList(); res56.add(res5); res56.add(res6); validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, res56, false), report); assertTrue(validation.isEmpty()); List res123 = new ArrayList(); res123.add(res1); res123.add(res2); res123.add(res3); validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, res123, false), report); assertTrue(validation.isEmpty()); List resAll = new ArrayList(); resAll.add(res1); resAll.add(res2); resAll.add(res3); resAll.add(res4); resAll.add(res5); resAll.add(res6); resAll.add(res7); validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, resAll, false), report); assertTrue(validation.isEmpty()); // publish cms.unlockProject(cms.getRequestContext().getCurrentProject().getUuid()); OpenCms.getPublishManager().publishProject(cms, report); OpenCms.getPublishManager().waitWhileRunning(); // check links after deletion touchResources(cms, resAll); validation = validateAfterDelete(cms, Collections.singletonList(res1), resAll, report); assertTrue(validation.isEmpty()); validation = validateAfterDelete(cms, Collections.singletonList(res2), resAll, report); assertEquals(validation.size(), 2); assertTrue(validation.keySet().contains(cms.getRequestContext().addSiteRoot(filename1))); assertTrue(validation.keySet().contains(cms.getRequestContext().addSiteRoot(filename4))); brokenLinks = (List)validation.get(cms.getRequestContext().addSiteRoot(filename1)); assertEquals(brokenLinks.size(), (mode == MODE_XMLCONTENT_BOTH ? 2 : 1)); assertTrue(brokenLinks.contains(new CmsRelation(res1, res2, relType1))); if (mode == MODE_XMLCONTENT_BOTH) { assertTrue(brokenLinks.contains(new CmsRelation(res1, res2, CmsRelationType.XML_WEAK))); } brokenLinks = (List)validation.get(cms.getRequestContext().addSiteRoot(filename4)); assertEquals(brokenLinks.size(), (mode == MODE_XMLCONTENT_BOTH ? 2 : 1)); assertTrue(brokenLinks.contains(new CmsRelation(res4, res2, relType1))); if (mode == MODE_XMLCONTENT_BOTH) { assertTrue(brokenLinks.contains(new CmsRelation(res4, res2, CmsRelationType.XML_WEAK))); } validation = validateAfterDelete(cms, Collections.singletonList(res3), resAll, report); assertEquals(validation.size(), 1); assertTrue(validation.keySet().contains(cms.getRequestContext().addSiteRoot(filename1))); brokenLinks = (List)validation.get(cms.getRequestContext().addSiteRoot(filename1)); assertEquals(brokenLinks.size(), 1); assertTrue(brokenLinks.contains(new CmsRelation(res1, res3, relType1))); validation = validateAfterDelete(cms, Collections.singletonList(res4), resAll, report); assertTrue(validation.isEmpty()); validation = validateAfterDelete(cms, Collections.singletonList(res5), resAll, report); assertEquals(validation.size(), 1); assertTrue(validation.keySet().contains(cms.getRequestContext().addSiteRoot(filename6))); brokenLinks = (List)validation.get(cms.getRequestContext().addSiteRoot(filename6)); assertEquals(brokenLinks.size(), (mode == MODE_XMLCONTENT_BOTH ? 2 : 1)); assertTrue(brokenLinks.contains(new CmsRelation(res6, res5, relType1))); if (mode == MODE_XMLCONTENT_BOTH) { assertTrue(brokenLinks.contains(new CmsRelation(res6, res5, CmsRelationType.XML_WEAK))); } validation = validateAfterDelete(cms, Collections.singletonList(res6), resAll, report); assertEquals(validation.size(), 1); assertTrue(validation.keySet().contains(cms.getRequestContext().addSiteRoot(filename5))); brokenLinks = (List)validation.get(cms.getRequestContext().addSiteRoot(filename5)); assertEquals(brokenLinks.size(), (mode == MODE_XMLCONTENT_BOTH ? 2 : 1)); assertTrue(brokenLinks.contains(new CmsRelation(res5, res6, relType1))); if (mode == MODE_XMLCONTENT_BOTH) { assertTrue(brokenLinks.contains(new CmsRelation(res5, res6, CmsRelationType.XML_WEAK))); } validation = validateAfterDelete(cms, Collections.singletonList(res7), resAll, report); assertTrue(validation.isEmpty()); validation = validateAfterDelete(cms, res56, resAll, report); assertTrue(validation.isEmpty()); // check links after modification // Publishing after deleting file5 and changing the link // from file6 on file5 to file7 must generate no errors CmsResource file5 = cms.readResource(filename5); // keeping the id for restoration delete(cms, filename5, report); switch (mode) { case 1: setXmlContent(cms, filename6, "<a href='" + filename7 + "'>file7</a>", filename7); break; case 2: setXmlContentHtml(cms, filename6, "<a href='" + filename7 + "'>file7</a>"); break; case 3: setXmlContentFileRef(cms, filename6, filename7, null); break; default: setContent(cms, filename6, "<a href='" + filename7 + "'>file7</a>"); break; } List resources = new ArrayList(resAll); resources.remove(res5); cms.unlockProject(cms.getRequestContext().getCurrentProject().getUuid()); validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, resources, false), report); assertTrue(validation.isEmpty()); switch (mode) { case 1: setXmlContent(cms, filename6, content6, filename5); break; case 2: setXmlContentHtml(cms, filename6, content6); break; case 3: setXmlContentFileRef(cms, filename6, filename5, null); break; default: setContent(cms, filename6, content6); break; } restore(cms, file5, report); // Publishing after deleting file2 and changing the link from file4 on file2 to file7 // and removing the link from file1 on file2 must generate no errors CmsResource file2 = cms.readResource(filename2); // keeping id for restoration delete(cms, filename2, report); switch (mode) { case 1: setXmlContent(cms, filename1, "no link!", null); setXmlContent(cms, filename4, "<a href='" + filename7 + "'>file7</a>", filename7); break; case 2: setXmlContentHtml(cms, filename1, "no link!"); setXmlContentHtml(cms, filename4, "<a href='" + filename7 + "'>file7</a>"); break; case 3: setXmlContentFileRef(cms, filename1, null, null); setXmlContentFileRef(cms, filename4, filename7, null); break; default: setContent(cms, filename1, "no link!"); setContent(cms, filename4, "<a href='" + filename7 + "'>file7</a>"); break; } resources = new ArrayList(resAll); resources.remove(res2); cms.unlockProject(cms.getRequestContext().getCurrentProject().getUuid()); validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, resources, false), report); assertTrue(validation.isEmpty()); switch (mode) { case 1: setXmlContent(cms, filename1, content1, filename2); setXmlContent(cms, filename4, content4, filename2); break; case 2: setXmlContentHtml(cms, filename1, content1); setXmlContentHtml(cms, filename4, content4); break; case 3: setXmlContentFileRef(cms, filename1, filename2, filename3); setXmlContentFileRef(cms, filename4, filename2, null); break; default: setContent(cms, filename1, content1); setContent(cms, filename4, content4); break; } restore(cms, file2, report); // Publishing just file7 after creating a new file8 and creating a link // from file7 to file8 must generate one error CmsResource res8 = cms.createResource(filename8, type); switch (mode) { case 1: setXmlContent(cms, filename7, "<a href='" + filename8 + "'>file8</a>", filename8); break; case 2: setXmlContentHtml(cms, filename7, "<a href='" + filename8 + "'>file8</a>"); break; case 3: setXmlContentFileRef(cms, filename7, filename8, null); break; default: setContent(cms, filename7, "<a href='" + filename8 + "'>file8</a>"); break; } cms.unlockProject(cms.getRequestContext().getCurrentProject().getUuid()); validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, Collections.singletonList(res7), false), report); assertEquals(validation.size(), 1); assertTrue(validation.keySet().contains(cms.getRequestContext().addSiteRoot(filename7))); brokenLinks = (List)validation.get(cms.getRequestContext().addSiteRoot(filename7)); assertEquals(brokenLinks.size(), (mode == MODE_XMLCONTENT_BOTH ? 2 : 1)); assertTrue(brokenLinks.contains(new CmsRelation(res7, res8, relType1))); if (mode == MODE_XMLCONTENT_BOTH) { assertTrue(brokenLinks.contains(new CmsRelation(res7, res8, CmsRelationType.XML_WEAK))); } // Publishing after creating a new file8 and creating a link // from file7 to file8 must generate no errors List res78 = new ArrayList(); res78.add(res7); res78.add(res8); validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, res78, false), report); assertTrue(validation.isEmpty()); // Linking file8 to file7 switch (mode) { case 1: setXmlContent(cms, filename8, "<a href='" + filename7 + "'>file7</a>", filename7); break; case 2: setXmlContentHtml(cms, filename8, "<a href='" + filename7 + "'>file7</a>"); break; case 3: setXmlContentFileRef(cms, filename8, filename7, null); break; default: setContent(cms, filename8, "<a href='" + filename7 + "'>file7</a>"); break; } // first publish OpenCms.getPublishManager().publishResource(cms, filename7); OpenCms.getPublishManager().publishResource(cms, filename8); OpenCms.getPublishManager().waitWhileRunning(); // now check the link validation if you want to delete one of them cms.lockResource(filename7); cms.deleteResource(filename7, CmsResource.DELETE_PRESERVE_SIBLINGS); cms.unlockProject(cms.getRequestContext().getCurrentProject().getUuid()); validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList( cms, Collections.singletonList(cms.readResource(filename7, CmsResourceFilter.ALL)), false), report); assertEquals(validation.size(), 1); assertTrue(validation.keySet().contains(cms.getRequestContext().addSiteRoot(filename7))); brokenLinks = (List)validation.get(cms.getRequestContext().addSiteRoot(filename7)); assertEquals(brokenLinks.size(), (mode == MODE_XMLCONTENT_BOTH ? 2 : 1)); assertTrue(brokenLinks.contains(new CmsRelation(res8, res7, relType1))); if (mode == MODE_XMLCONTENT_BOTH) { assertTrue(brokenLinks.contains(new CmsRelation(res8, res7, CmsRelationType.XML_WEAK))); } // then check the link if you want to delete them together cms.lockResource(filename8); cms.deleteResource(filename8, CmsResource.DELETE_PRESERVE_SIBLINGS); cms.unlockProject(cms.getRequestContext().getCurrentProject().getUuid()); res78 = new ArrayList(); res78.add(cms.readResource(filename7, CmsResourceFilter.ALL)); res78.add(cms.readResource(filename8, CmsResourceFilter.ALL)); validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, res78, false), report); assertTrue(validation.isEmpty()); } /** * Touch all resources in the given list.<p> * * @param cms the cms context * @param resources the resources to touch * @throws CmsException if something goes wrong */ private void touchResources(CmsObject cms, List resources) throws CmsException { Iterator it = resources.iterator(); while (it.hasNext()) { CmsResource resource = (CmsResource)it.next(); String resName = cms.getRequestContext().removeSiteRoot(resource.getRootPath()); cms.lockResource(resName); cms.setDateLastModified(resName, System.currentTimeMillis(), false); } } /** * Validates the links after the deletion of all the given resources.<p> * * @param cms the cms context * @param resources the resources to delete * @param allResources the resource context * @param report the report * * @return the validation map * * @throws Exception if something goes wrong */ private Map validateAfterDelete(CmsObject cms, List resources, List allResources, CmsShellReport report) throws Exception { List otherRes = new ArrayList(allResources); Iterator itRes = resources.iterator(); while (itRes.hasNext()) { CmsResource resource = (CmsResource)itRes.next(); String resName = cms.getRequestContext().getSitePath(resource); delete(cms, resName, report); otherRes.remove(resource); } cms.unlockProject(cms.getRequestContext().getCurrentProject().getUuid()); Map validation = OpenCms.getPublishManager().validateRelations( cms, OpenCms.getPublishManager().getPublishList(cms, otherRes, false), report); itRes = resources.iterator(); while (itRes.hasNext()) { CmsResource resource = (CmsResource)itRes.next(); restore(cms, resource, report); } touchResources(cms, resources); return validation; } }