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.inherited.CmsInheritanceGroupUtils;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsProperty;
033import org.opencms.file.CmsPropertyDefinition;
034import org.opencms.file.CmsResource;
035import org.opencms.file.CmsResourceFilter;
036import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
037import org.opencms.file.types.I_CmsResourceType;
038import org.opencms.gwt.shared.CmsBrokenLinkBean;
039import org.opencms.main.CmsException;
040import org.opencms.main.CmsLog;
041import org.opencms.main.OpenCms;
042import org.opencms.relations.CmsRelation;
043import org.opencms.relations.CmsRelationFilter;
044import org.opencms.util.CmsUUID;
045
046import java.util.ArrayList;
047import java.util.List;
048import java.util.Locale;
049import java.util.Set;
050
051import org.apache.commons.logging.Log;
052
053/**
054 * A helper class used to generate the necessary information for displaying links which will be broken
055 * if the user tries to delete a file in the ADE GUI.<p>
056 */
057public class CmsBrokenLinkRenderer {
058
059    /** The logger instance for this class.*/
060    private static final Log LOG = CmsLog.getLog(CmsBrokenLinkRenderer.class);
061
062    /** The CMS context used by the broken link renderer.<p> */
063    private CmsObject m_cms;
064
065    /**
066     * Creates a new broken link renderer instance.<p>
067     *
068     * @param cms the current CMS context
069     */
070    public CmsBrokenLinkRenderer(CmsObject cms) {
071
072        m_cms = cms;
073    }
074
075    /**
076     * Renders the source of a broken link as a list of CmsBrokenLinkBean instances.<p>
077     *
078     * @param target the broken link target
079     * @param source the broken link source
080     * @return the list of broken link beans to display to the user
081     *
082     * @throws CmsException if something goes wrong
083     */
084    public List<CmsBrokenLinkBean> renderBrokenLink(CmsResource target, CmsResource source) throws CmsException {
085
086        I_CmsResourceType resType = OpenCms.getResourceManager().getResourceType(source);
087        String typeName = resType.getTypeName();
088        if (typeName.equals(CmsResourceTypeXmlContainerPage.INHERIT_CONTAINER_CONFIG_TYPE_NAME)) {
089            return renderBrokenLinkInheritanceGroup(target, source);
090        } else if (CmsResourceTypeXmlContainerPage.GROUP_CONTAINER_TYPE_NAME.equals(typeName)) {
091            return renderBrokenLinkGroupContainer(target, source);
092        } else {
093            return renderBrokenLinkDefault(target, source);
094        }
095    }
096
097    /**
098     * The default method for rendering broken link sources.<p>
099     *
100     * @param target the link target
101     * @param source the link source
102     * @return the list of broken link beans to display to the user
103     *
104     * @throws CmsException if something goes wrong
105     */
106    public List<CmsBrokenLinkBean> renderBrokenLinkDefault(CmsResource target, CmsResource source) throws CmsException {
107
108        List<CmsBrokenLinkBean> result = new ArrayList<CmsBrokenLinkBean>();
109        result.add(createSitemapBrokenLinkBean(source));
110        return result;
111    }
112
113    /**
114     * Renders the broken links for a group container.<p>
115     *
116     * @param target the broken link target
117     * @param source the broken link source
118     *
119     * @return the list of broken link beans to display to the user
120     *
121     * @throws CmsException if something goes wrong
122     */
123    public List<CmsBrokenLinkBean> renderBrokenLinkGroupContainer(CmsResource target, CmsResource source)
124    throws CmsException {
125
126        List<CmsBrokenLinkBean> result = new ArrayList<CmsBrokenLinkBean>();
127        CmsBrokenLinkBean brokenLinkBean = createSitemapBrokenLinkBean(source);
128        result.add(brokenLinkBean);
129        try {
130            CmsResource referencingPage = findReferencingPage(source);
131            if (referencingPage != null) {
132                String pagePath = m_cms.getRequestContext().removeSiteRoot(referencingPage.getRootPath());
133                String title = CmsResource.getName(pagePath);
134                CmsProperty titleProp = m_cms.readPropertyObject(
135                    referencingPage,
136                    CmsPropertyDefinition.PROPERTY_TITLE,
137                    false);
138                if (!titleProp.isNullProperty()) {
139                    title = titleProp.getValue();
140                }
141                addPageInfo(brokenLinkBean, title, pagePath);
142            }
143        } catch (CmsException e) {
144            LOG.warn(e.getLocalizedMessage(), e);
145        }
146        return result;
147    }
148
149    /**
150     * Renders broken links from an inheritance group.<p>
151     *
152     * @param target the link target
153     * @param source the link source
154     *
155     * @return the list of broken link beans to display to the user
156     *
157     * @throws CmsException if something goes wrong
158     */
159    public List<CmsBrokenLinkBean> renderBrokenLinkInheritanceGroup(CmsResource target, CmsResource source)
160    throws CmsException {
161
162        List<CmsBrokenLinkBean> result = new ArrayList<CmsBrokenLinkBean>();
163        try {
164            Set<String> names = CmsInheritanceGroupUtils.getNamesOfGroupsContainingResource(m_cms, source, target);
165            if (!names.isEmpty()) {
166                for (String name : names) {
167                    String title = null;
168                    String path = null;
169                    String extraTitle = null;
170                    String extraPath = null;
171
172                    CmsResource group = CmsInheritanceGroupUtils.getInheritanceGroupContentByName(m_cms, name);
173                    String groupParent = CmsResource.getParentFolder(source.getRootPath());
174                    CmsProperty titleProp = m_cms.readPropertyObject(
175                        group,
176                        CmsPropertyDefinition.PROPERTY_TITLE,
177                        false);
178                    title = CmsResource.getName(group.getRootPath());
179                    if (!titleProp.isNullProperty()) {
180                        title = titleProp.getValue();
181                    }
182                    path = m_cms.getRequestContext().removeSiteRoot(source.getRootPath());
183                    List<CmsRelation> relations = m_cms.readRelations(
184                        CmsRelationFilter.relationsToStructureId(group.getStructureId()));
185                    List<CmsResource> referencingPages = new ArrayList<CmsResource>();
186                    for (CmsRelation relation : relations) {
187                        CmsResource relSource = relation.getSource(m_cms, CmsResourceFilter.ALL);
188                        String pageParent = CmsResource.getParentFolder(relSource.getRootPath());
189                        if (CmsResourceTypeXmlContainerPage.isContainerPage(relSource)
190                            && pageParent.equals(groupParent)) {
191                            referencingPages.add(relSource);
192                        }
193                    }
194                    if (!referencingPages.isEmpty()) {
195                        CmsResource firstPage = referencingPages.get(0);
196                        extraPath = m_cms.getRequestContext().removeSiteRoot(firstPage.getRootPath());
197                        extraTitle = m_cms.readPropertyObject(
198                            firstPage,
199                            CmsPropertyDefinition.PROPERTY_TITLE,
200                            true).getValue();
201                    }
202                    result.add(
203                        createBrokenLinkBean(
204                            group.getStructureId(),
205                            CmsResourceTypeXmlContainerPage.INHERIT_CONTAINER_CONFIG_TYPE_NAME,
206                            title,
207                            path,
208                            extraTitle,
209                            extraPath));
210                }
211            } else {
212                result.add(createSitemapBrokenLinkBean(source));
213            }
214        } catch (CmsException e) {
215            result.add(createSitemapBrokenLinkBean(source));
216        }
217        return result;
218    }
219
220    /**
221     * Adds optional page information to the broken link bean.<p>
222     *
223     * @param bean the broken link bean
224     * @param extraTitle the optional page title
225     * @param extraPath the optional page path
226     */
227    protected void addPageInfo(CmsBrokenLinkBean bean, String extraTitle, String extraPath) {
228
229        if (extraTitle != null) {
230            bean.addInfo(messagePageTitle(), "" + extraTitle);
231        }
232        if (extraPath != null) {
233            bean.addInfo(messagePagePath(), "" + extraPath);
234        }
235    }
236
237    /**
238     * Creates a broken link bean from the necessary values.<p>
239     *
240     * @param structureId the structure id of the resource
241     * @param type the resource type
242     * @param title the title
243     * @param path the path
244     * @param extraTitle an optional additional page title
245     * @param extraPath an optional additional page path
246     *
247     * @return the created broken link bean
248     */
249    protected CmsBrokenLinkBean createBrokenLinkBean(
250        CmsUUID structureId,
251        String type,
252        String title,
253        String path,
254        String extraTitle,
255        String extraPath) {
256
257        CmsBrokenLinkBean result = new CmsBrokenLinkBean(structureId, title, path, type);
258        addPageInfo(result, extraTitle, extraPath);
259        return result;
260    }
261
262    /**
263     * Creates a "broken link" bean based on a resource.<p>
264     *
265     * @param resource the resource
266     * @return the "broken link" bean with the data from the resource
267     *
268     * @throws CmsException if something goes wrong
269     */
270    protected CmsBrokenLinkBean createSitemapBrokenLinkBean(CmsResource resource) throws CmsException {
271
272        CmsProperty titleProp = m_cms.readPropertyObject(resource, CmsPropertyDefinition.PROPERTY_TITLE, true);
273        String typeName = OpenCms.getResourceManager().getResourceType(resource).getTypeName();
274        String defaultTitle = CmsResource.getName(resource.getRootPath());
275        String title = titleProp.getValue(defaultTitle);
276        String path = m_cms.getSitePath(resource);
277        String subtitle = path;
278        return new CmsBrokenLinkBean(resource.getStructureId(), title, subtitle, typeName);
279    }
280
281    /**
282     * Finds a page which references another resource.<p>
283     *
284     * @param source a resource
285     * @return a page which references the resource, or null if no such page was found.
286     *
287     * @throws CmsException if something goes wrong
288     */
289    private CmsResource findReferencingPage(CmsResource source) throws CmsException {
290
291        List<CmsRelation> relationsToFile = m_cms.readRelations(
292            CmsRelationFilter.relationsToStructureId(source.getStructureId()));
293        for (CmsRelation relation : relationsToFile) {
294            try {
295                CmsResource referencingPage = relation.getSource(m_cms, CmsResourceFilter.DEFAULT);
296                if (CmsResourceTypeXmlContainerPage.isContainerPage(referencingPage)) {
297                    return referencingPage;
298                }
299            } catch (CmsException e) {
300                LOG.info(e.getLocalizedMessage(), e);
301            }
302        }
303        return null;
304    }
305
306    /**
307     * Gets the workplace locale.<p>
308     *
309     * @return the workplace locale
310     */
311    private Locale getLocale() {
312
313        return OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms);
314    }
315
316    /**
317     * Message accessor.<p>
318     *
319     * @return the message
320     */
321    private String messagePagePath() {
322
323        return org.opencms.gwt.Messages.get().getBundle(getLocale()).key(
324            org.opencms.gwt.Messages.GUI_DEPENDENCY_PAGE_PATH_0);
325    }
326
327    /**
328     * Message accessor.<p>
329     *
330     * @return the message
331     */
332    private String messagePageTitle() {
333
334        return org.opencms.gwt.Messages.get().getBundle(getLocale()).key(
335            org.opencms.gwt.Messages.GUI_DEPENDENCY_PAGE_TITLE_0);
336    }
337
338}