You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by bu...@apache.org on 2009/10/17 11:12:39 UTC

svn commit: r826205 - in /ofbiz/trunk: applications/content/ applications/content/data/ applications/content/src/org/ofbiz/content/cms/ applications/content/webapp/content/WEB-INF/actions/website/ applications/content/webapp/content/website/ specialpur...

Author: buscob
Date: Sat Oct 17 09:12:39 2009
New Revision: 826205

URL: http://svn.apache.org/viewvc?rev=826205&view=rev
Log:
A patch from Patrick Antivackis "Addind Error Pages (404 - 410) possibilities for the Content app" (https://issues.apache.org/jira/browse/OFBIZ-3022) - OFBIZ-3022

Added:
    ofbiz/trunk/applications/content/data/ContentHttpErrorData.xml
Modified:
    ofbiz/trunk/applications/content/data/ContentTypeData.xml
    ofbiz/trunk/applications/content/ofbiz-component.xml
    ofbiz/trunk/applications/content/src/org/ofbiz/content/cms/CmsEvents.java
    ofbiz/trunk/applications/content/webapp/content/WEB-INF/actions/website/WebSitePublishPoint.groovy
    ofbiz/trunk/applications/content/webapp/content/website/WebSiteCMSNav.ftl
    ofbiz/trunk/specialpurpose/cmssite/data/CmsSiteDemoData.xml

Added: ofbiz/trunk/applications/content/data/ContentHttpErrorData.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/data/ContentHttpErrorData.xml?rev=826205&view=auto
==============================================================================
--- ofbiz/trunk/applications/content/data/ContentHttpErrorData.xml (added)
+++ ofbiz/trunk/applications/content/data/ContentHttpErrorData.xml Sat Oct 17 09:12:39 2009
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF 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
+
+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.
+-->
+<entity-engine-xml>
+    <Content contentId="CONTENT_ERROR" contentTypeId="DOCUMENT" contentName="Generic CMS Error Pages"/>
+    <ContentAssoc contentId="TREE_ROOT" contentIdTo="CONTENT_ERROR" contentAssocTypeId="TREE_CHILD" fromDate="2006-01-12 01:01:01"/>
+    <DataResource dataResourceId="CONTENT_ERROR_403" dataResourceTypeId="ELECTRONIC_TEXT" dataTemplateTypeId="FTL"/>
+    <ElectronicText dataResourceId="CONTENT_ERROR_403">
+        <textData><![CDATA[<html><head><title>Access Forbidden</title></head><body>${statusCode?if_exists} Forbidden</body></html>]]></textData>
+    </ElectronicText>
+    <Content contentId="CONTENT_ERROR_403" contentTypeId="DOCUMENT" contentName="Generic CMS 403 Access Forbidden" dataResourceId="CONTENT_ERROR_403"/>
+    <DataResource dataResourceId="CONTENT_ERROR_404" dataResourceTypeId="ELECTRONIC_TEXT" dataTemplateTypeId="FTL"/>
+    <ElectronicText dataResourceId="CONTENT_ERROR_404">
+        <textData><![CDATA[<html><head><title>Page not found</title></head><body>${statusCode?if_exists} Not Found</body></html>]]></textData>
+    </ElectronicText>
+    <ContentAssoc contentId="CONTENT_ERROR" contentIdTo="CONTENT_ERROR_403" contentAssocTypeId="SUB_CONTENT" fromDate="2006-01-12 01:01:01"/>
+    <Content contentId="CONTENT_ERROR_404" contentTypeId="DOCUMENT" contentName="Generic CMS 404 Page Not Found" dataResourceId="CONTENT_ERROR_404"/>
+    <ContentAssoc contentId="CONTENT_ERROR" contentIdTo="CONTENT_ERROR_404" contentAssocTypeId="SUB_CONTENT" fromDate="2006-01-12 01:01:01"/>
+    <DataResource dataResourceId="CONTENT_ERROR_404_FR" dataResourceTypeId="ELECTRONIC_TEXT" localeString="fr_FR" dataTemplateTypeId="FTL"/>
+    <ElectronicText dataResourceId="CONTENT_ERROR_404_FR">
+        <textData><![CDATA[<html><head><title>Page inconnue</title></head><body>${statusCode?if_exists} Page Inconnue</body></html>]]></textData>
+    </ElectronicText>
+    <Content contentId="CONTENT_ERROR_404_FR" contentTypeId="DOCUMENT" contentName="Page 404 inconnue générique" dataResourceId="CONTENT_ERROR_404_FR" localeString="fr_FR"/>
+    <ContentAssoc contentId="CONTENT_ERROR" contentIdTo="CONTENT_ERROR_404_FR" contentAssocTypeId="SUB_CONTENT" fromDate="2006-01-12 01:01:01"/>
+    <ContentAssoc contentId="CONTENT_ERROR_404" contentIdTo="CONTENT_ERROR_404_FR" contentAssocTypeId="ALTERNATE_LOCALE" fromDate="2001-01-01 00:00:00"/>
+    <DataResource dataResourceId="CONTENT_ERROR_410" dataResourceTypeId="ELECTRONIC_TEXT" dataTemplateTypeId="FTL"/>
+    <ElectronicText dataResourceId="CONTENT_ERROR_410">
+        <textData><![CDATA[<html><head><title>Page is gone</title></head><body>${statusCode?if_exists} Page is gone</body></html>]]></textData>
+    </ElectronicText>
+    <Content contentId="CONTENT_ERROR_410" contentTypeId="DOCUMENT" contentName="Generic CMS 410 Page Is Gone" dataResourceId="CONTENT_ERROR_410"/>
+    <ContentAssoc contentId="CONTENT_ERROR" contentIdTo="CONTENT_ERROR_410" contentAssocTypeId="SUB_CONTENT" fromDate="2006-01-12 01:01:01"/>
+</entity-engine-xml>

Modified: ofbiz/trunk/applications/content/data/ContentTypeData.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/data/ContentTypeData.xml?rev=826205&r1=826204&r2=826205&view=diff
==============================================================================
--- ofbiz/trunk/applications/content/data/ContentTypeData.xml (original)
+++ ofbiz/trunk/applications/content/data/ContentTypeData.xml Sat Oct 17 09:12:39 2009
@@ -190,6 +190,7 @@
     <WebSiteContentType webSiteContentTypeId="DEFAULT_PAGE" description="Default Page" hasTable="N" parentTypeId=""/>
     <WebSiteContentType webSiteContentTypeId="FORUM_ROOT" description="Forum Root" hasTable="N" parentTypeId=""/>
     <WebSiteContentType webSiteContentTypeId="MENU_ROOT" description="Menu Containers" hasTable="N" parentTypeId=""/>
+    <WebSiteContentType webSiteContentTypeId="ERROR_ROOT" description="Error Page Containers" hasTable="N" parentTypeId=""/>
     <WebSiteContentType webSiteContentTypeId="PUBLISH_POINT" description="Publish Point" hasTable="N" parentTypeId=""/>
 
     <!-- survey data -->

Modified: ofbiz/trunk/applications/content/ofbiz-component.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/ofbiz-component.xml?rev=826205&r1=826204&r2=826205&view=diff
==============================================================================
--- ofbiz/trunk/applications/content/ofbiz-component.xml (original)
+++ ofbiz/trunk/applications/content/ofbiz-component.xml Sat Oct 17 09:12:39 2009
@@ -38,6 +38,7 @@
     <entity-resource type="data" reader-name="seed" loader="main" location="data/ContentSecurityData.xml"/>
     <entity-resource type="data" reader-name="seed" loader="main" location="data/MiscData.xml"/>
     <entity-resource type="data" reader-name="seed" loader="main" location="data/ContentHelpData.xml"/>
+    <entity-resource type="data" reader-name="seed" loader="main" location="data/ContentHttpErrorData.xml"/>
     <!-- these files cannot be loaded in their original component because they are earlier than the content component -->
     <entity-resource type="data" reader-name="seed" loader="main" location="data/PartyHelpData.xml"/>
     <entity-resource type="data" reader-name="seed" loader="main" location="data/WebtoolsHelpData.xml"/>

Modified: ofbiz/trunk/applications/content/src/org/ofbiz/content/cms/CmsEvents.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/src/org/ofbiz/content/cms/CmsEvents.java?rev=826205&r1=826204&r2=826205&view=diff
==============================================================================
--- ofbiz/trunk/applications/content/src/org/ofbiz/content/cms/CmsEvents.java (original)
+++ ofbiz/trunk/applications/content/src/org/ofbiz/content/cms/CmsEvents.java Sat Oct 17 09:12:39 2009
@@ -31,6 +31,7 @@
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
 import javax.servlet.http.HttpSession;
 
 import org.ofbiz.base.util.Debug;
@@ -183,25 +184,81 @@
             }
 
             // verify the request content is associated with the current website
-            boolean websiteOk;
+            int statusCode=-1;
+            boolean hasErrorPage=false;
+            
             try {
-                websiteOk = verifyContentToWebSite(delegator, webSiteId, contentId);
+                statusCode = verifyContentToWebSite(delegator, webSiteId, contentId);
             } catch (GeneralException e) {
                 Debug.logError(e, module);
                 throw new GeneralRuntimeException(e.getMessage(), e);
             }
+            
+            // We try to find a specific Error page for this website concerning the status code
+            if (statusCode!=HttpServletResponseWrapper.SC_OK) {
+                List<GenericValue> errorContainers = null;
+                try {
+                    errorContainers = delegator.findByAndCache("WebSiteContent",
+                            UtilMisc.toMap("webSiteId", webSiteId, "webSiteContentTypeId", "ERROR_ROOT"),
+                            UtilMisc.toList("-fromDate"));
+                } catch (GenericEntityException e) {
+                    Debug.logError(e, module);
+                }
 
-            if (websiteOk) {
+                errorContainers = EntityUtil.filterByDate(errorContainers);
+                if (UtilValidate.isNotEmpty(errorContainers)) {
+                    if (Debug.verboseOn()) Debug.logVerbose("Found error containers: " + errorContainers, module);
+                    GenericValue errorContainer = EntityUtil.getFirst(errorContainers);
+                    
+                    List<GenericValue> errorPages = null;
+                    try {
+                        errorPages = delegator.findByAnd("ContentAssocViewTo", UtilMisc.toMap("contentIdStart", errorContainer.getString("contentId"), "caContentAssocTypeId", "TREE_CHILD", "contentTypeId", "DOCUMENT", "caMapKey",""+statusCode));    
+                    } catch (GenericEntityException e) {
+                        Debug.logError(e, module);
+                    }
+                    errorPages = EntityUtil.filterByDate(errorPages);
+                    if (UtilValidate.isNotEmpty(errorPages)) {
+                        if (Debug.verboseOn()) Debug.logVerbose("Found error pages "+ statusCode + " : " + errorPages, module);
+                        contentId=EntityUtil.getFirst(errorPages).getString("contentId");
+                    }
+                    else {
+                        if (Debug.verboseOn()) Debug.logVerbose("No specific error page, falling back to the Error Container for "+ statusCode, module);
+                        contentId=errorContainer.getString("contentId");
+                    }
+                    mapKey = null;
+                    hasErrorPage=true;
+                }
+                // We try to find a generic content Error page concerning the status code
+                if (!hasErrorPage) {
+                    try {
+                        GenericValue errorPage = delegator.findByPrimaryKeyCache("Content", UtilMisc.toMap("contentId", "CONTENT_ERROR_"+statusCode));
+                        if (errorPage!=null) {
+                            Debug.logVerbose("Found generic page " + statusCode, module);
+                            contentId=errorPage.getString("contentId");
+                            mapKey = null;
+                            hasErrorPage=true;
+                        }
+                    } catch (GenericEntityException e) {
+                        Debug.logError(e, module);
+                    }                    
+                }
+
+            }
+            
+            if (statusCode==HttpServletResponseWrapper.SC_OK || hasErrorPage) {
                 // create the template map
                 MapStack<String> templateMap = MapStack.create();
                 ScreenRenderer.populateContextForRequest(templateMap, null, request, response, servletContext);
                 templateMap.put("formStringRenderer", new HtmlFormRenderer(request, response));
+                templateMap.put("statusCode", statusCode);
 
                 // make the link prefix
                 ServletContext ctx = (ServletContext) request.getAttribute("servletContext");
                 RequestHandler rh = (RequestHandler) ctx.getAttribute("_REQUEST_HANDLER_");
                 templateMap.put("_REQUEST_HANDLER_", rh);
 
+                response.setStatus(statusCode);
+                
                 // NOTE DEJ20080817: this is done in the ContentMapFacade class now to avoid problems with the jsessionid being in the middle of the URL and such
                 //String contextLinkPrefix = rh.makeLink(request, response, "", true, false, true);
                 //templateMap.put("_CONTEXT_LINK_PREFIX_", contextLinkPrefix);
@@ -239,9 +296,13 @@
                 String siteName = null;
                 try {
                     GenericValue content = delegator.findByPrimaryKeyCache("Content", UtilMisc.toMap("contentId", contentId));
-                    if (UtilValidate.isNotEmpty(content)) {
+                    if (content !=null && UtilValidate.isNotEmpty(content)) {
                         contentName = content.getString("contentName");
                     }
+                    else {
+                        request.setAttribute("_ERROR_MESSAGE_", "Content: " + contentName + " [" + contentId + "] is not a publish point for the current website: [" + webSiteId + "]");
+                        return "error";
+                    }
                     siteName = delegator.findByPrimaryKeyCache("WebSite", UtilMisc.toMap("webSiteId", webSiteId)).getString("siteName");
                 } catch (GenericEntityException e) {
                     Debug.logError(e, module);
@@ -262,9 +323,10 @@
         //throw new GeneralRuntimeException("Unknown request; this request does not exist or cannot be called directly.");
     }
 
-    protected static boolean verifyContentToWebSite(Delegator delegator, String webSiteId, String contentId) throws GeneralException {
+    protected static int verifyContentToWebSite(Delegator delegator, String webSiteId, String contentId) throws GeneralException {
         // first check if the passed in contentId is a publish point for the web site
         List<GenericValue> publishPoints = null;
+        boolean hasContent=false;
         try {
             publishPoints = delegator.findByAndCache("WebSiteContent",
                     UtilMisc.toMap("webSiteId", webSiteId, "contentId", contentId, "webSiteContentTypeId", "PUBLISH_POINT"),
@@ -272,47 +334,60 @@
         } catch (GenericEntityException e) {
             throw e;
         }
-
+        if (UtilValidate.isNotEmpty(publishPoints)) {
+            hasContent=true;
+        }
         publishPoints = EntityUtil.filterByDate(publishPoints);
         if (UtilValidate.isNotEmpty(publishPoints)) {
             if (Debug.verboseOn()) Debug.logVerbose("Found publish points: " + publishPoints, module);
-            return true;
+            return HttpServletResponseWrapper.SC_OK;
         } else {
             // the passed in contentId is not a publish point for the web site;
             // however we will publish its content if it is a node of one of the trees that have a publish point as the root
             List<GenericValue> topLevelContentValues = delegator.findByAndCache("WebSiteContent",
                 UtilMisc.toMap("webSiteId", webSiteId, "webSiteContentTypeId", "PUBLISH_POINT"), UtilMisc.toList("-fromDate"));
             topLevelContentValues = EntityUtil.filterByDate(topLevelContentValues);
+
             if (topLevelContentValues != null) {
                 for (GenericValue point: topLevelContentValues) {
-                    if (verifySubContent(delegator, contentId, point.getString("contentId"))) {
-                        return true;
+                    int subContentStatusCode=verifySubContent(delegator, contentId, point.getString("contentId"));
+                    if (subContentStatusCode== HttpServletResponseWrapper.SC_OK) {
+                        return HttpServletResponseWrapper.SC_OK;
+                    } else if (subContentStatusCode== HttpServletResponseWrapper.SC_GONE) {
+                        hasContent=true;
                     }
                 }
             }
         }
-
-        return false;
+        if (hasContent) return HttpServletResponseWrapper.SC_GONE;
+        return HttpServletResponseWrapper.SC_NOT_FOUND;
     }
 
-    protected static boolean verifySubContent(Delegator delegator, String contentId, String contentIdFrom) throws GeneralException {
+    protected static int verifySubContent(Delegator delegator, String contentId, String contentIdFrom) throws GeneralException {
         List<GenericValue> contentAssoc = delegator.findByAnd("ContentAssoc", UtilMisc.toMap("contentId", contentIdFrom, "contentIdTo", contentId, "contentAssocTypeId", "SUB_CONTENT"));
+        boolean hasContent=false;
+        if (UtilValidate.isNotEmpty(contentAssoc)) {
+            hasContent=true;
+        }
         contentAssoc = EntityUtil.filterByDate(contentAssoc);
         if (contentAssoc == null || contentAssoc.size() == 0) {
             List<GenericValue> assocs = delegator.findByAnd("ContentAssoc", UtilMisc.toMap("contentId", contentIdFrom));
             assocs = EntityUtil.filterByDate(assocs);
             if (assocs != null) {
                 for (GenericValue assoc: assocs) {
-                    if (verifySubContent(delegator, contentId, assoc.getString("contentIdTo"))) {
-                        return true;
+                    int subContentStatusCode=verifySubContent(delegator, contentId, assoc.getString("contentIdTo"));
+                    if (subContentStatusCode== HttpServletResponseWrapper.SC_OK) {
+                        return HttpServletResponseWrapper.SC_OK;
+                    } else if (subContentStatusCode== HttpServletResponseWrapper.SC_GONE) {
+                        hasContent=true;
                     }
                 }
             }
         } else {
             if (Debug.verboseOn()) Debug.logVerbose("Found assocs: " + contentAssoc, module);
-            return true;
+            return HttpServletResponseWrapper.SC_OK;
         }
-
-        return false;
+        if (hasContent) return HttpServletResponseWrapper.SC_GONE;
+        return HttpServletResponseWrapper.SC_NOT_FOUND;
     }
 }

Modified: ofbiz/trunk/applications/content/webapp/content/WEB-INF/actions/website/WebSitePublishPoint.groovy
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/webapp/content/WEB-INF/actions/website/WebSitePublishPoint.groovy?rev=826205&r1=826204&r2=826205&view=diff
==============================================================================
--- ofbiz/trunk/applications/content/webapp/content/WEB-INF/actions/website/WebSitePublishPoint.groovy (original)
+++ ofbiz/trunk/applications/content/webapp/content/WEB-INF/actions/website/WebSitePublishPoint.groovy Sat Oct 17 09:12:39 2009
@@ -44,7 +44,21 @@
     context.menu = menu;
     context.menuRoot = menuRoot;
 
-    // get all sub content for the publish point
+    // get all sub content for the menu root
     menus = delegator.findList("ContentAssoc", EntityCondition.makeCondition([contentId : menuRoot]), null, null, null, false);
     context.menus = menus;
+}
+
+erlookupMap = [webSiteId : webSiteId, webSiteContentTypeId : 'ERROR_ROOT'];
+webSiteErrors = delegator.findList("WebSiteContent", EntityCondition.makeCondition(erlookupMap), null, ['-fromDate'], null, false);
+webSiteError = EntityUtil.getFirst(webSiteErrors);
+if (webSiteError) {
+    error = webSiteError.getRelatedOne("Content");
+    errorRoot = error.contentId;
+    context.error = error;
+    context.errorRoot = errorRoot;
+
+    // get all sub content for the error root
+    errors = delegator.findList("ContentAssoc", EntityCondition.makeCondition([contentId : errorRoot]), null, null, null, false);
+    context.errors = errors;
 }
\ No newline at end of file

Modified: ofbiz/trunk/applications/content/webapp/content/website/WebSiteCMSNav.ftl
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/content/webapp/content/website/WebSiteCMSNav.ftl?rev=826205&r1=826204&r2=826205&view=diff
==============================================================================
--- ofbiz/trunk/applications/content/webapp/content/website/WebSiteCMSNav.ftl (original)
+++ ofbiz/trunk/applications/content/webapp/content/website/WebSiteCMSNav.ftl Sat Oct 17 09:12:39 2009
@@ -410,4 +410,30 @@
 </div>
 <#if (!menus?has_content)>
     <a href="javascript:void(0);" class="buttontext">${uiLabelMap.ContentWebSiteAddMenu}</a>
+</#if>
+
+<div>&nbsp;</div>
+<div>&nbsp;</div>
+
+<dl dojoType="TreeContextMenu" id="webErrorContextMenu" style="font-size: 1em; color: #ccc;">
+    <dt dojoType="TreeMenuItem" id="newErrorPage" caption="New Error Page"/>
+</dl>
+
+<div class="label">
+    ${uiLabelMap.ContentWebSiteErrors}
+</div>
+<div>
+    ${uiLabelMap.ContentWebSiteAddNewErrors}
+</div>
+<div>&nbsp;</div>
+
+<dojo:TreeSelector widgetId="webErrorTreeSelector" eventNames="select:webErrorNodeSelected"></dojo:TreeSelector>
+<div dojoType="Tree" menu="webErrorContextMenu" widgetId="webErrorTree" selector="webErrorTreeSelector" toggler="fade" toggleDuration="500">
+    <#if (errors?has_content)>
+        ${errors}
+        <@fillTree assocList = errors/>
+    </#if>
+</div>
+<#if (!errors?has_content)>
+    <a href="javascript:void(0);" class="buttontext">${uiLabelMap.ContentWebSiteAddError}</a>
 </#if>
\ No newline at end of file

Modified: ofbiz/trunk/specialpurpose/cmssite/data/CmsSiteDemoData.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/cmssite/data/CmsSiteDemoData.xml?rev=826205&r1=826204&r2=826205&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/cmssite/data/CmsSiteDemoData.xml (original)
+++ ofbiz/trunk/specialpurpose/cmssite/data/CmsSiteDemoData.xml Sat Oct 17 09:12:39 2009
@@ -161,8 +161,21 @@
                 <br/><br/>
         ]]></textData>
     </ElectronicText>
-
-
+    
+    <!-- Specific Error Pages -->
+    <DataResource dataResourceId="CMSS_ERROR_ROOT" dataResourceTypeId="ELECTRONIC_TEXT" dataTemplateTypeId="FTL"/>
+    <ElectronicText dataResourceId="CMSS_ERROR_ROOT">
+        <textData><![CDATA[<html><head><title>Status Code : ${statusCode?if_exists}</title></head><body>Error ${statusCode?if_exists}</body></html>]]></textData>
+    </ElectronicText>
+    <Content contentId="CMSS_ERROR_ROOT" contentTypeId="DOCUMENT"
+        contentName="CMS Site Error Page Container" dataResourceId="CMSS_ERROR_ROOT"/>
+    <WebSiteContent webSiteId="CmsSite" contentId="CMSS_ERROR_ROOT" webSiteContentTypeId="ERROR_ROOT" fromDate="2001-01-01 00:00:00"/>
+    <DataResource dataResourceId="CMSS_ERROR_404" dataResourceTypeId="ELECTRONIC_TEXT" dataTemplateTypeId="FTL"/>
+    <ElectronicText dataResourceId="CMSS_ERROR_404">
+        <textData><![CDATA[<html><head><title>cmsSite : Page not found</title></head><body>cmsSite : ${statusCode?if_exists} Not Found</body></html>]]></textData>
+    </ElectronicText>
+    <Content contentId="CMSS_ERROR_404" contentTypeId="DOCUMENT" contentName="Specific CMS 404 Page Not Found For CmsSite" dataResourceId="CMSS_ERROR_404"/>
+    <ContentAssoc contentId="CMSS_ERROR_ROOT" contentIdTo="CMSS_ERROR_404" contentAssocTypeId="TREE_CHILD" fromDate="2001-01-01 00:00:00" mapKey="404"/>
 
     <!--
       CmsSite (WebSite)