001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (C) Alkacon Software (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, 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.gwt;
029
030import org.opencms.ade.containerpage.CmsContainerpageService;
031import org.opencms.ade.containerpage.CmsDetailOnlyContainerUtil;
032import org.opencms.ade.containerpage.CmsRelationTargetListBean;
033import org.opencms.file.CmsFile;
034import org.opencms.file.CmsObject;
035import org.opencms.file.CmsProperty;
036import org.opencms.file.CmsPropertyDefinition;
037import org.opencms.file.CmsResource;
038import org.opencms.file.CmsResourceFilter;
039import org.opencms.file.CmsUser;
040import org.opencms.file.CmsVfsResourceNotFoundException;
041import org.opencms.file.types.CmsResourceTypeJsp;
042import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
043import org.opencms.file.types.CmsResourceTypeXmlContent;
044import org.opencms.file.types.I_CmsResourceType;
045import org.opencms.gwt.shared.CmsGwtConstants;
046import org.opencms.gwt.shared.CmsListInfoBean;
047import org.opencms.gwt.shared.CmsPermissionInfo;
048import org.opencms.gwt.shared.CmsResourceStatusBean;
049import org.opencms.gwt.shared.CmsResourceStatusRelationBean;
050import org.opencms.gwt.shared.CmsResourceStatusTabId;
051import org.opencms.i18n.CmsLocaleManager;
052import org.opencms.i18n.CmsMessageContainer;
053import org.opencms.lock.CmsLock;
054import org.opencms.main.CmsException;
055import org.opencms.main.CmsLog;
056import org.opencms.main.OpenCms;
057import org.opencms.relations.CmsRelation;
058import org.opencms.relations.CmsRelationFilter;
059import org.opencms.relations.CmsRelationType;
060import org.opencms.relations.I_CmsLinkParseable;
061import org.opencms.search.galleries.CmsGallerySearch;
062import org.opencms.search.galleries.CmsGallerySearchResult;
063import org.opencms.security.CmsRole;
064import org.opencms.site.CmsSite;
065import org.opencms.util.CmsStringUtil;
066import org.opencms.util.CmsUUID;
067import org.opencms.workplace.CmsWorkplace;
068import org.opencms.workplace.explorer.CmsResourceUtil;
069import org.opencms.xml.containerpage.CmsContainerElementBean;
070import org.opencms.xml.containerpage.I_CmsFormatterBean;
071import org.opencms.xml.content.CmsXmlContent;
072import org.opencms.xml.content.CmsXmlContentFactory;
073
074import java.util.ArrayList;
075import java.util.Arrays;
076import java.util.Collections;
077import java.util.Comparator;
078import java.util.HashMap;
079import java.util.Iterator;
080import java.util.LinkedHashMap;
081import java.util.List;
082import java.util.Locale;
083import java.util.Map;
084import java.util.Set;
085
086import javax.servlet.http.HttpServletRequest;
087
088import org.apache.commons.logging.Log;
089
090import com.google.common.base.Optional;
091import com.google.common.collect.ComparisonChain;
092import com.google.common.collect.Maps;
093import com.google.common.collect.Sets;
094
095/**
096 * Helper class to generate all the data which is necessary for the resource status dialog(s).<p>
097 */
098public class CmsDefaultResourceStatusProvider {
099
100    /** The detail container path pattern. */
101    private static final String DETAIL_CONTAINER_PATTERN = ".*\\/\\.detailContainers\\/.*";
102
103    /** The log instance for this class. */
104    private static final Log LOG = CmsLog.getLog(CmsDefaultResourceStatusProvider.class);
105
106    /**
107     * Gets the relation targets for a resource.<p>
108     *
109     * @param cms the current CMS context
110     * @param source the structure id of the resource for which we want the relation targets
111     * @param additionalIds the structure ids of additional resources to include with the relation targets
112     * @param cancelIfChanged if this is true, this method will stop immediately if it finds a changed resource among the relation targets
113     *
114     * @return a bean containing a list of relation targets
115     *
116     * @throws CmsException if something goes wrong
117     */
118    public static CmsRelationTargetListBean getContainerpageRelationTargets(
119        CmsObject cms,
120        CmsUUID source,
121        List<CmsUUID> additionalIds,
122        boolean cancelIfChanged)
123    throws CmsException {
124
125        CmsRelationTargetListBean result = new CmsRelationTargetListBean();
126        CmsResource content = cms.readResource(source, CmsResourceFilter.ALL);
127        boolean isContainerPage = CmsResourceTypeXmlContainerPage.isContainerPage(content);
128        if (additionalIds != null) {
129            for (CmsUUID structureId : additionalIds) {
130                try {
131                    CmsResource res = cms.readResource(structureId, CmsResourceFilter.ALL);
132                    result.add(res);
133                    if (res.getState().isChanged() && cancelIfChanged) {
134                        return result;
135                    }
136                } catch (CmsException e) {
137                    LOG.error(e.getLocalizedMessage(), e);
138                }
139            }
140        }
141        List<CmsRelation> relations = cms.readRelations(CmsRelationFilter.relationsFromStructureId(source));
142        for (CmsRelation relation : relations) {
143            if (relation.getType() == CmsRelationType.XSD) {
144                continue;
145            }
146            try {
147                CmsResource target = relation.getTarget(cms, CmsResourceFilter.ALL);
148                I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(target);
149                if (isContainerPage && (type instanceof CmsResourceTypeJsp)) {
150                    // ignore formatters for container pages, as the normal user probably doesn't want to deal with them
151                    continue;
152                }
153                result.add(target);
154                if (target.getState().isChanged() && cancelIfChanged) {
155                    return result;
156                }
157            } catch (CmsException e) {
158                LOG.debug(e.getLocalizedMessage(), e);
159            }
160        }
161        return result;
162    }
163
164    /**
165     * Collects all the data to display in the resource status dialog.<p>
166     *
167     * @param request the current request
168     * @param cms the current CMS context
169     * @param structureId the structure id of the resource for which we want the information
170     * @param contentLocale the content locale
171     * @param includeTargets true if relation targets should be included
172     * @param detailContentId the structure id of the detail content if present
173     * @param additionalStructureIds structure ids of additional resources to include with the relation targets
174     * @param context context parameters used for displaying additional infos
175     *
176     * @return the resource status information
177     * @throws CmsException if something goes wrong
178     */
179    public CmsResourceStatusBean getResourceStatus(
180        HttpServletRequest request,
181        CmsObject cms,
182        CmsUUID structureId,
183        String contentLocale,
184        boolean includeTargets,
185        CmsUUID detailContentId,
186        List<CmsUUID> additionalStructureIds,
187        Map<String, String> context)
188    throws CmsException {
189
190        Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
191        cms.getRequestContext().setLocale(locale);
192        CmsResource resource = cms.readResource(structureId, CmsResourceFilter.ALL);
193        String localizedTitle = null;
194        Locale realLocale = null;
195        if (!CmsStringUtil.isEmptyOrWhitespaceOnly(contentLocale)) {
196            realLocale = CmsLocaleManager.getLocale(contentLocale);
197            CmsGallerySearchResult result = CmsGallerySearch.searchById(cms, structureId, realLocale);
198            if (!CmsStringUtil.isEmptyOrWhitespaceOnly(result.getTitle())) {
199                localizedTitle = result.getTitle();
200            }
201        }
202        CmsResourceUtil resourceUtil = new CmsResourceUtil(cms, resource);
203        List<CmsProperty> properties = cms.readPropertyObjects(resource, false);
204        CmsResourceStatusBean result = new CmsResourceStatusBean();
205        result.setDateCreated(CmsVfsService.formatDateTime(cms, resource.getDateCreated()));
206        long dateExpired = resource.getDateExpired();
207        if (dateExpired != CmsResource.DATE_EXPIRED_DEFAULT) {
208            result.setDateExpired(CmsVfsService.formatDateTime(cms, dateExpired));
209        }
210        result.setDateLastModified(CmsVfsService.formatDateTime(cms, resource.getDateLastModified()));
211        long dateReleased = resource.getDateReleased();
212        if (dateReleased != CmsResource.DATE_RELEASED_DEFAULT) {
213            result.setDateReleased(CmsVfsService.formatDateTime(cms, dateReleased));
214        }
215        String lastProject = resourceUtil.getLockedInProjectName();
216        if ("".equals(lastProject)) {
217            lastProject = null;
218        }
219        result.setLastProject(lastProject);
220
221        result.setListInfo(CmsVfsService.getPageInfo(cms, resource));
222        Map<String, String> contextualAddInfos = createContextInfos(cms, request, resource, context);
223        for (Map.Entry<String, String> entry : contextualAddInfos.entrySet()) {
224            result.getListInfo().addAdditionalInfo(entry.getKey(), entry.getValue());
225        }
226
227        CmsLock lock = cms.getLock(resource);
228        CmsUser lockOwner = null;
229        if (!lock.isUnlocked()) {
230            lockOwner = cms.readUser(lock.getUserId());
231            result.setLockState(
232                org.opencms.workplace.list.Messages.get().getBundle(locale).key(
233                    org.opencms.workplace.list.Messages.GUI_EXPLORER_LIST_ACTION_LOCK_NAME_2,
234                    lockOwner.getName(),
235                    lastProject));
236        } else {
237            result.setLockState(
238                org.opencms.workplace.list.Messages.get().getBundle(locale).key(
239                    org.opencms.workplace.list.Messages.GUI_EXPLORER_LIST_ACTION_UNLOCK_NAME_0));
240        }
241
242        CmsProperty navText = CmsProperty.get(CmsPropertyDefinition.PROPERTY_NAVTEXT, properties);
243        if (navText != null) {
244            result.setNavText(navText.getValue());
245        }
246        result.setPermissions(resourceUtil.getPermissionString());
247        result.setSize(resource.getLength());
248        result.setStateBean(resource.getState());
249        CmsProperty title = CmsProperty.get(CmsPropertyDefinition.PROPERTY_TITLE, properties);
250        if (localizedTitle != null) {
251            result.setTitle(localizedTitle);
252            result.getListInfo().setTitle(localizedTitle);
253        } else if (title != null) {
254            result.setTitle(title.getValue());
255        }
256        result.setUserCreated(resourceUtil.getUserCreated());
257        result.setUserLastModified(resourceUtil.getUserLastModified());
258
259        I_CmsResourceType resType = OpenCms.getResourceManager().getResourceType(resource);
260        result.setResourceType(resType.getTypeName());
261
262        result.setStructureId(resource.getStructureId());
263        if (resType instanceof CmsResourceTypeXmlContent) {
264            CmsFile file = cms.readFile(resource);
265            CmsXmlContent content = CmsXmlContentFactory.unmarshal(cms, file);
266            List<Locale> locales = content.getLocales();
267            List<String> localeStrings = new ArrayList<String>();
268            for (Locale l : locales) {
269                localeStrings.add(l.toString());
270            }
271            result.setLocales(localeStrings);
272        }
273        Map<String, String> additionalAttributes = new LinkedHashMap<String, String>();
274        additionalAttributes.put(
275            Messages.get().getBundle(locale).key(Messages.GUI_STATUS_PERMALINK_0),
276            OpenCms.getLinkManager().getPermalink(cms, cms.getSitePath(resource), detailContentId));
277
278        if (OpenCms.getRoleManager().hasRole(cms, CmsRole.ADMINISTRATOR)) {
279            additionalAttributes.put(
280                Messages.get().getBundle(locale).key(Messages.GUI_STATUS_STRUCTURE_ID_0),
281                resource.getStructureId().toString());
282            additionalAttributes.put(
283                Messages.get().getBundle(locale).key(Messages.GUI_STATUS_RESOURCE_ID_0),
284                resource.getResourceId().toString());
285        }
286
287        result.setAdditionalAttributes(additionalAttributes);
288
289        List<CmsRelation> relations = cms.readRelations(
290            CmsRelationFilter.relationsToStructureId(resource.getStructureId()));
291        Map<CmsUUID, CmsResource> relationSources = new HashMap<CmsUUID, CmsResource>();
292
293        if (CmsResourceTypeXmlContainerPage.isContainerPage(resource)) {
294            // People may link to the folder of a container page instead of the page itself
295            try {
296                CmsResource parent = cms.readParentFolder(resource.getStructureId());
297                List<CmsRelation> parentRelations = cms.readRelations(
298                    CmsRelationFilter.relationsToStructureId(parent.getStructureId()));
299                relations.addAll(parentRelations);
300            } catch (CmsException e) {
301                LOG.error(e.getLocalizedMessage(), e);
302            }
303        }
304
305        // find all distinct relation sources
306        for (CmsRelation relation : relations) {
307            try {
308                CmsResource currentSource = relation.getSource(cms, CmsResourceFilter.ALL);
309                relationSources.put(currentSource.getStructureId(), currentSource);
310            } catch (CmsException e) {
311                LOG.error(e.getLocalizedMessage(), e);
312            }
313        }
314
315        for (CmsResource relationResource : relationSources.values()) {
316            try {
317                CmsPermissionInfo permissionInfo = OpenCms.getADEManager().getPermissionInfo(
318                    cms,
319                    relationResource,
320                    resource.getRootPath());
321                if (permissionInfo.hasViewPermission()) {
322                    CmsResourceStatusRelationBean relationBean = createRelationBean(
323                        cms,
324                        contentLocale,
325                        relationResource,
326                        permissionInfo);
327                    CmsSite site = OpenCms.getSiteManager().getSiteForRootPath(relationResource.getRootPath());
328                    if ((site != null)
329                        && !CmsStringUtil.isPrefixPath(
330                            cms.getRequestContext().getSiteRoot(),
331                            relationResource.getRootPath())) {
332                        String siteTitle = site.getTitle();
333                        if (siteTitle == null) {
334                            siteTitle = site.getUrl();
335                        } else {
336                            siteTitle = CmsWorkplace.substituteSiteTitleStatic(
337                                siteTitle,
338                                OpenCms.getWorkplaceManager().getWorkplaceLocale(cms));
339                        }
340                        relationBean.setSiteRoot(site.getSiteRoot());
341                        result.getOtherSiteRelationSources().add(relationBean);
342                        relationBean.getInfoBean().setTitle(
343                            "[" + siteTitle + "] " + relationBean.getInfoBean().getTitle());
344                    } else {
345                        result.getRelationSources().add(relationBean);
346                    }
347
348                }
349            } catch (CmsVfsResourceNotFoundException notfound) {
350                LOG.error(notfound.getLocalizedMessage(), notfound);
351                continue;
352            }
353        }
354        sortRelations(cms, result);
355        if (includeTargets) {
356            result.getRelationTargets().addAll(getTargets(cms, contentLocale, resource, additionalStructureIds));
357            if ((detailContentId != null) && (realLocale != null)) {
358                // try to add detail only contents
359                try {
360                    CmsResource detailContent = cms.readResource(detailContentId, CmsResourceFilter.ALL);
361                    Optional<CmsResource> detailOnlyPage = CmsDetailOnlyContainerUtil.getDetailOnlyResource(
362                        cms,
363                        realLocale.toString(),
364                        detailContent,
365                        resource);
366                    if (detailOnlyPage.isPresent()) {
367                        result.getRelationTargets().addAll(
368                            getTargets(
369                                cms,
370                                contentLocale,
371                                detailOnlyPage.get(),
372                                Arrays.asList(detailOnlyPage.get().getStructureId())));
373                    }
374
375                } catch (CmsException e) {
376                    LOG.error(e.getLocalizedMessage(), e);
377                }
378            }
379            Iterator<CmsResourceStatusRelationBean> iter = result.getRelationTargets().iterator();
380            // Remove duplicates
381            Set<CmsUUID> visitedIds = Sets.newHashSet();
382            while (iter.hasNext()) {
383                CmsResourceStatusRelationBean bean = iter.next();
384                if (visitedIds.contains(bean.getStructureId())) {
385                    iter.remove();
386                }
387                visitedIds.add(bean.getStructureId());
388            }
389        }
390        result.getSiblings().addAll(getSiblings(cms, contentLocale, resource));
391        LinkedHashMap<CmsResourceStatusTabId, String> tabMap = new LinkedHashMap<CmsResourceStatusTabId, String>();
392        Map<CmsResourceStatusTabId, CmsMessageContainer> tabs;
393        CmsResourceStatusTabId startTab = CmsResourceStatusTabId.tabRelationsFrom;
394        if (CmsResourceTypeXmlContainerPage.isContainerPage(resource)) {
395            tabs = CmsResourceStatusConstants.STATUS_TABS_CONTAINER_PAGE;
396        } else if (OpenCms.getResourceManager().getResourceType(resource) instanceof I_CmsLinkParseable) {
397            tabs = CmsResourceStatusConstants.STATUS_TABS_CONTENT;
398        } else {
399            tabs = CmsResourceStatusConstants.STATUS_TABS_OTHER;
400            startTab = CmsResourceStatusTabId.tabStatus;
401        }
402        for (Map.Entry<CmsResourceStatusTabId, CmsMessageContainer> entry : tabs.entrySet()) {
403            tabMap.put(entry.getKey(), entry.getValue().key(locale));
404        }
405
406        result.setTabs(tabMap);
407        result.setStartTab(startTab);
408        return result;
409    }
410
411    /**
412     * Sorts relation beans from other sites by site order.<p>
413     *
414     * @param cms the current CMS context
415     * @param resStatus the bean in which to sort the relation beans
416     */
417    public void sortRelations(CmsObject cms, CmsResourceStatusBean resStatus) {
418
419        final List<CmsSite> sites = OpenCms.getSiteManager().getAvailableSites(
420            cms,
421            false,
422            false,
423            cms.getRequestContext().getOuFqn());
424        Collections.sort(resStatus.getOtherSiteRelationSources(), new Comparator<CmsResourceStatusRelationBean>() {
425
426            private Map<String, Integer> m_rankCache = Maps.newHashMap();
427
428            public int compare(CmsResourceStatusRelationBean o1, CmsResourceStatusRelationBean o2) {
429
430                return ComparisonChain.start().compare(rank(o1), rank(o2)).compare(
431                    o1.getSitePath(),
432                    o2.getSitePath()).result();
433
434            }
435
436            public int rank(CmsResourceStatusRelationBean r) {
437
438                if (m_rankCache.containsKey(r.getSiteRoot())) {
439                    return m_rankCache.get(r.getSiteRoot()).intValue();
440                }
441
442                int j = 0;
443                int result = Integer.MAX_VALUE;
444                for (CmsSite site : sites) {
445                    if (site.getSiteRoot().equals(r.getSiteRoot())) {
446                        result = j;
447                        break;
448                    }
449                    j += 1;
450                }
451
452                m_rankCache.put(r.getSiteRoot(), new Integer(result));
453                return result;
454            }
455        });
456        // sort relation sources by path, make sure all resources within .detailContainer folders show last
457        Collections.sort(resStatus.getRelationSources(), new Comparator<CmsResourceStatusRelationBean>() {
458
459            public int compare(CmsResourceStatusRelationBean arg0, CmsResourceStatusRelationBean arg1) {
460
461                if (arg0.getSitePath().matches(DETAIL_CONTAINER_PATTERN)) {
462                    if (!arg1.getSitePath().matches(DETAIL_CONTAINER_PATTERN)) {
463                        return 1;
464                    }
465                } else if (arg1.getSitePath().matches(DETAIL_CONTAINER_PATTERN)) {
466                    return -1;
467                }
468                return arg0.getSitePath().compareTo(arg1.getSitePath());
469            }
470
471        });
472    }
473
474    /**
475     * Gets beans which represents the siblings of a resource.<p>
476     *
477     * @param cms the CMS ccontext
478     * @param locale the locale
479     * @param resource the resource
480     * @return the list of sibling beans
481     *
482     * @throws CmsException if something goes wrong
483     */
484    protected List<CmsResourceStatusRelationBean> getSiblings(CmsObject cms, String locale, CmsResource resource)
485    throws CmsException {
486
487        List<CmsResourceStatusRelationBean> result = new ArrayList<CmsResourceStatusRelationBean>();
488        for (CmsResource sibling : cms.readSiblings(resource, CmsResourceFilter.ALL)) {
489            if (sibling.getStructureId().equals(resource.getStructureId())) {
490                continue;
491            }
492            try {
493                CmsPermissionInfo permissionInfo = OpenCms.getADEManager().getPermissionInfo(
494                    cms,
495                    sibling,
496                    resource.getRootPath());
497                if (permissionInfo.hasViewPermission()) {
498                    CmsResourceStatusRelationBean relationBean = createRelationBean(
499                        cms,
500                        locale,
501                        sibling,
502                        permissionInfo);
503                    result.add(relationBean);
504                }
505            } catch (CmsException e) {
506                LOG.error(e.getLocalizedMessage(), e);
507            }
508        }
509        return result;
510    }
511
512    /**
513     * Gets the list of relation targets for a resource.<p>
514     *
515     * @param cms the current CMS context
516     * @param locale the locale
517     * @param resource the resource for which we want the relation targets
518     * @param additionalStructureIds structure ids of additional resources to include with the relation target
519     *
520     * @return the list of relation beans for the relation targets
521     *
522     * @throws CmsException if something goes wrong
523     */
524    protected List<CmsResourceStatusRelationBean> getTargets(
525        CmsObject cms,
526        String locale,
527        CmsResource resource,
528        List<CmsUUID> additionalStructureIds)
529    throws CmsException {
530
531        CmsRelationTargetListBean listBean = getContainerpageRelationTargets(
532            cms,
533            resource.getStructureId(),
534            additionalStructureIds,
535            false);
536        List<CmsResourceStatusRelationBean> result = new ArrayList<CmsResourceStatusRelationBean>();
537        for (CmsResource target : listBean.getResources()) {
538            try {
539                CmsPermissionInfo permissionInfo = OpenCms.getADEManager().getPermissionInfo(
540                    cms,
541                    target,
542                    resource.getRootPath());
543                if (permissionInfo.hasViewPermission()) {
544                    CmsResourceStatusRelationBean relationBean = createRelationBean(
545                        cms,
546                        locale,
547                        target,
548                        permissionInfo);
549                    result.add(relationBean);
550                }
551            } catch (CmsException e) {
552                LOG.error(e.getLocalizedMessage(), e);
553            }
554        }
555        return result;
556
557    }
558
559    /**
560     * Creates a bean for a single resource which is part of a relation list.<p>
561     *
562     * @param cms the current CMS context
563     * @param locale the locale
564     * @param relationResource the resource
565     * @param permissionInfo the permission info
566     *
567     * @return the status bean for the resource
568     *
569     * @throws CmsException if something goes wrong
570     */
571    CmsResourceStatusRelationBean createRelationBean(
572        CmsObject cms,
573        String locale,
574        CmsResource relationResource,
575        CmsPermissionInfo permissionInfo)
576    throws CmsException {
577
578        CmsListInfoBean sourceBean = CmsVfsService.getPageInfo(cms, relationResource);
579        sourceBean.setMarkChangedState(true);
580        sourceBean.setResourceState(relationResource.getState());
581
582        if (!CmsStringUtil.isEmptyOrWhitespaceOnly(locale)) {
583            Locale realLocale = CmsLocaleManager.getLocale(locale);
584            CmsGallerySearchResult result = CmsGallerySearch.searchById(
585                cms,
586                relationResource.getStructureId(),
587                realLocale);
588            if (!CmsStringUtil.isEmptyOrWhitespaceOnly(result.getTitle())) {
589                sourceBean.setTitle(result.getTitle());
590            }
591        }
592        String link = null;
593        try {
594            link = OpenCms.getLinkManager().substituteLink(cms, relationResource);
595        } catch (Exception e) {
596            LOG.warn(e.getLocalizedMessage(), e);
597        }
598        CmsResourceStatusRelationBean relationBean = new CmsResourceStatusRelationBean(
599            sourceBean,
600            link,
601            relationResource.getStructureId(),
602            permissionInfo);
603        if (CmsResourceTypeXmlContent.isXmlContent(relationResource)) {
604            relationBean.setIsXmlContent(true);
605        }
606        String sitePath = cms.getSitePath(relationResource);
607        relationBean.setSitePath(sitePath);
608        return relationBean;
609    }
610
611    /**
612     * Creates the additional infos from the context parameters.<p>
613     *
614     * @param cms the current CMS object
615     * @param request the current request
616     * @param resource the resource for which to generate additional infos
617     * @param context the context parameters
618     * @return the additional infos (keys are labels)
619     *
620     */
621    private Map<String, String> createContextInfos(
622        CmsObject cms,
623        HttpServletRequest request,
624        CmsResource resource,
625        Map<String, String> context) {
626
627        Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
628        Map<String, String> additionalAttributes = new LinkedHashMap<String, String>();
629        try {
630            try {
631                CmsRelationFilter filter = CmsRelationFilter.relationsFromStructureId(
632                    resource.getStructureId()).filterType(CmsRelationType.XSD);
633                String schema = null;
634                String label = org.opencms.ade.containerpage.Messages.get().getBundle(locale).key(
635                    org.opencms.ade.containerpage.Messages.GUI_ADDINFO_SCHEMA_0);
636
637                for (CmsRelation relation : cms.readRelations(filter)) {
638                    CmsResource target = relation.getTarget(cms, CmsResourceFilter.IGNORE_EXPIRATION);
639                    schema = target.getRootPath();
640                    break;
641                }
642                if (schema != null) {
643                    additionalAttributes.put(label, schema);
644                }
645            } catch (CmsException e) {
646                LOG.error(e.getLocalizedMessage(), e);
647            }
648
649            String elementId = context.get(CmsGwtConstants.ATTR_ELEMENT_ID);
650            String pageRootPath = context.get(CmsGwtConstants.ATTR_PAGE_ROOT_PATH);
651            String containr = context.get(CmsGwtConstants.ATTR_CONTAINER_ID);
652            // We need to handle the case of normal formatter element vs display formatter differently,
653            // because in the former case the jsp id is sometimes incorrect (i.e. inconsistent with the formatter configured in the settings)
654            if ((elementId != null) && (containr != null)) {
655                CmsContainerpageService pageService = new CmsContainerpageService();
656                pageService.setCms(cms);
657                pageService.setRequest(request);
658                CmsContainerElementBean elementBean = pageService.getCachedElement(elementId, pageRootPath);
659                for (Map.Entry<String, String> entry : elementBean.getSettings().entrySet()) {
660                    if (entry.getKey().contains(containr)) {
661                        String formatterId = entry.getValue();
662                        if (CmsUUID.isValidUUID(formatterId)) {
663                            I_CmsFormatterBean formatter = OpenCms.getADEManager().getCachedFormatters(
664                                false).getFormatters().get(new CmsUUID(formatterId));
665                            if (formatter != null) {
666                                String label = org.opencms.ade.containerpage.Messages.get().getBundle(locale).key(
667                                    org.opencms.ade.containerpage.Messages.GUI_ADDINFO_FORMATTER_0);
668                                additionalAttributes.put(label, formatter.getJspRootPath());
669                            }
670                        }
671                    }
672                }
673            } else if ((elementId != null) && (pageRootPath != null)) {
674                CmsContainerpageService pageService = new CmsContainerpageService();
675                pageService.setCms(cms);
676                pageService.setRequest(request);
677                CmsContainerElementBean elementBean = pageService.getCachedElement(elementId, pageRootPath);
678                CmsUUID formatterId = elementBean.getFormatterId();
679                try {
680                    CmsResource formatterRes = cms.readResource(formatterId, CmsResourceFilter.IGNORE_EXPIRATION);
681                    String path = formatterRes.getRootPath();
682                    String label = org.opencms.ade.containerpage.Messages.get().getBundle(locale).key(
683                        org.opencms.ade.containerpage.Messages.GUI_ADDINFO_FORMATTER_0);
684                    additionalAttributes.put(label, path);
685                } catch (CmsVfsResourceNotFoundException e) {
686                    // ignore
687                } catch (CmsException e) {
688                    LOG.error(e.getLocalizedMessage(), e);
689                }
690            }
691        } catch (Exception e) {
692            LOG.error(e.getLocalizedMessage(), e);
693        }
694
695        return additionalAttributes;
696    }
697}