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                    String icon = CmsIconUtil.getIconClasses(
203                        CmsIconUtil.getDisplayType(m_cms, source),
204                        source.getName(),
205                        false);
206                    result.add(
207
208                        createBrokenLinkBean(
209                            group.getStructureId(),
210                            CmsResourceTypeXmlContainerPage.INHERIT_CONTAINER_CONFIG_TYPE_NAME,
211                            title,
212                            path,
213                            extraTitle,
214                            extraPath,
215                            icon));
216                }
217            } else {
218                result.add(createSitemapBrokenLinkBean(source));
219            }
220        } catch (CmsException e) {
221            result.add(createSitemapBrokenLinkBean(source));
222        }
223        return result;
224    }
225
226    /**
227     * Adds optional page information to the broken link bean.<p>
228     *
229     * @param bean the broken link bean
230     * @param extraTitle the optional page title
231     * @param extraPath the optional page path
232     */
233    protected void addPageInfo(CmsBrokenLinkBean bean, String extraTitle, String extraPath) {
234
235        if (extraTitle != null) {
236            bean.addInfo(messagePageTitle(), "" + extraTitle);
237        }
238        if (extraPath != null) {
239            bean.addInfo(messagePagePath(), "" + extraPath);
240        }
241    }
242
243    /**
244     * Creates a broken link bean from the necessary values.<p>
245     *
246     * @param structureId the structure id of the resource
247     * @param type the resource type
248     * @param title the title
249     * @param path the path
250     * @param icon the icon CSS classes
251     * @param extraTitle an optional additional page title
252     * @param extraPath an optional additional page path
253     *
254     * @return the created broken link bean
255     */
256    protected CmsBrokenLinkBean createBrokenLinkBean(
257        CmsUUID structureId,
258        String type,
259        String title,
260        String path,
261        String icon,
262        String extraTitle,
263        String extraPath) {
264
265        CmsBrokenLinkBean result = new CmsBrokenLinkBean(structureId, title, path, type, icon);
266        addPageInfo(result, extraTitle, extraPath);
267        return result;
268    }
269
270    /**
271     * Creates a "broken link" bean based on a resource.<p>
272     *
273     * @param resource the resource
274     * @return the "broken link" bean with the data from the resource
275     *
276     * @throws CmsException if something goes wrong
277     */
278    protected CmsBrokenLinkBean createSitemapBrokenLinkBean(CmsResource resource) throws CmsException {
279
280        CmsProperty titleProp = m_cms.readPropertyObject(resource, CmsPropertyDefinition.PROPERTY_TITLE, true);
281        String typeName = OpenCms.getResourceManager().getResourceType(resource).getTypeName();
282        String defaultTitle = CmsResource.getName(resource.getRootPath());
283        String title = titleProp.getValue(defaultTitle);
284        String path = m_cms.getSitePath(resource);
285        String icon = CmsIconUtil.getIconClasses(
286            CmsIconUtil.getDisplayType(m_cms, resource),
287            resource.getName(),
288            false);
289        String subtitle = path;
290        return new CmsBrokenLinkBean(resource.getStructureId(), title, subtitle, typeName, icon);
291    }
292
293    /**
294     * Finds a page which references another resource.<p>
295     *
296     * @param source a resource
297     * @return a page which references the resource, or null if no such page was found.
298     *
299     * @throws CmsException if something goes wrong
300     */
301    private CmsResource findReferencingPage(CmsResource source) throws CmsException {
302
303        List<CmsRelation> relationsToFile = m_cms.readRelations(
304            CmsRelationFilter.relationsToStructureId(source.getStructureId()));
305        for (CmsRelation relation : relationsToFile) {
306            try {
307                CmsResource referencingPage = relation.getSource(m_cms, CmsResourceFilter.DEFAULT);
308                if (CmsResourceTypeXmlContainerPage.isContainerPage(referencingPage)) {
309                    return referencingPage;
310                }
311            } catch (CmsException e) {
312                LOG.info(e.getLocalizedMessage(), e);
313            }
314        }
315        return null;
316    }
317
318    /**
319     * Gets the workplace locale.<p>
320     *
321     * @return the workplace locale
322     */
323    private Locale getLocale() {
324
325        return OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms);
326    }
327
328    /**
329     * Message accessor.<p>
330     *
331     * @return the message
332     */
333    private String messagePagePath() {
334
335        return org.opencms.gwt.Messages.get().getBundle(getLocale()).key(
336            org.opencms.gwt.Messages.GUI_DEPENDENCY_PAGE_PATH_0);
337    }
338
339    /**
340     * Message accessor.<p>
341     *
342     * @return the message
343     */
344    private String messagePageTitle() {
345
346        return org.opencms.gwt.Messages.get().getBundle(getLocale()).key(
347            org.opencms.gwt.Messages.GUI_DEPENDENCY_PAGE_TITLE_0);
348    }
349
350}