001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (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 GmbH & Co. KG, 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.jsp;
029
030import org.opencms.file.CmsObject;
031import org.opencms.flex.CmsFlexController;
032import org.opencms.i18n.CmsLocaleManager;
033import org.opencms.main.CmsException;
034import org.opencms.main.CmsLog;
035import org.opencms.main.OpenCms;
036import org.opencms.staticexport.CmsLinkManager;
037import org.opencms.util.CmsStringUtil;
038
039import java.util.Locale;
040
041import javax.servlet.ServletRequest;
042import javax.servlet.jsp.JspException;
043import javax.servlet.jsp.tagext.BodyTagSupport;
044
045import org.apache.commons.logging.Log;
046
047/**
048 * Implements the <code>&lt;cms:link&gt;[filename]&lt;/cms:link&gt;</code>
049 * tag to add OpenCms managed links to a JSP page, required for link
050 * management and the static
051 * export to work properly.<p>
052 *
053 * @since 6.0.0
054 */
055public class CmsJspTagLink extends BodyTagSupport {
056
057    /** The log object for this class. */
058    private static final Log LOG = CmsLog.getLog(CmsJspTagLink.class);
059
060    /** Serial version UID required for safe serialization. */
061    private static final long serialVersionUID = -2361021288258405388L;
062
063    /** The optional base URI to create the link from. */
064    private String m_baseUri;
065
066    /** The target detail page path. */
067    private String m_detailPage;
068
069    /** The optional locale attribute. */
070    private Locale m_locale;
071
072    /**
073     * Returns a link to a file in the OpenCms VFS
074     * that has been adjusted according to the web application path and the
075     * OpenCms static export rules.<p>
076     *
077     * The current OpenCms user context URI will be used as source of the link.</p>
078     *
079     * Since OpenCms version 7.0.2, you can also use this method in case you are not sure
080     * if the link is internal or external, as
081     * {@link CmsLinkManager#substituteLinkForUnknownTarget(org.opencms.file.CmsObject, String)}
082     * is used to calculate the link target.<p>
083     *
084     * Relative links are converted to absolute links, using the current element URI as base.<p>
085     *
086     * @param target the link that should be calculated, can be relative or absolute
087     * @param req the current request
088     *
089     * @return the target link adjusted according to the web application path and the OpenCms static export rules
090     *
091     * @see org.opencms.staticexport.CmsLinkManager#substituteLinkForUnknownTarget(org.opencms.file.CmsObject, String)
092     */
093    public static String linkTagAction(String target, ServletRequest req) {
094
095        return linkTagAction(target, req, null);
096    }
097
098    /**
099     * Returns a link to a file in the OpenCms VFS
100     * that has been adjusted according to the web application path and the
101     * OpenCms static export rules.<p>
102     *
103     * If the <code>baseUri</code> parameter is provided, this will be treated as the source of the link,
104     * if this is <code>null</code> then the current OpenCms user context URI will be used as source.</p>
105     *
106     * Relative links are converted to absolute links, using the current element URI as base.<p>
107     *
108     * @param target the link that should be calculated, can be relative or absolute
109     * @param req the current request
110     * @param baseUri the base URI for the link source
111     *
112     * @return the target link adjusted according to the web application path and the OpenCms static export rules
113     *
114     * @see #linkTagAction(String, ServletRequest)
115     *
116     * @since 8.0.3
117     */
118    public static String linkTagAction(String target, ServletRequest req, String baseUri) {
119
120        return linkTagAction(target, req, baseUri, null);
121    }
122
123    /**
124     * Returns a link to a file in the OpenCms VFS
125     * that has been adjusted according to the web application path and the
126     * OpenCms static export rules.<p>
127     *
128     * <p>If the <code>baseUri</code> parameter is provided, this will be treated as the source of the link,
129     * if this is <code>null</code> then the current OpenCms user context URI will be used as source.</p>
130     *
131     * <p>If the <code>locale</code> parameter is provided, the locale in the request context will be switched
132     * to the provided locale. This influences only the behavior of the
133     * {@link org.opencms.staticexport.CmsLocalePrefixLinkSubstitutionHandler}.</p>
134     *
135     *
136     * Relative links are converted to absolute links, using the current element URI as base.<p>
137     *
138     * @param target the link that should be calculated, can be relative or absolute
139     * @param req the current request
140     * @param baseUri the base URI for the link source
141     * @param locale the locale for which the link should be created (see {@link org.opencms.staticexport.CmsLocalePrefixLinkSubstitutionHandler}
142     *
143     * @return the target link adjusted according to the web application path and the OpenCms static export rules
144     *
145     * @see #linkTagAction(String, ServletRequest)
146     *
147     * @since 8.0.3
148     */
149    public static String linkTagAction(String target, ServletRequest req, String baseUri, Locale locale) {
150
151        return linkTagAction(target, req, baseUri, null, locale);
152    }
153
154    /**
155     * Returns a link to a file in the OpenCms VFS
156     * that has been adjusted according to the web application path and the
157     * OpenCms static export rules.<p>
158     *
159     * <p>If the <code>baseUri</code> parameter is provided, this will be treated as the source of the link,
160     * if this is <code>null</code> then the current OpenCms user context URI will be used as source.</p>
161     *
162     * <p>If the <code>locale</code> parameter is provided, the locale in the request context will be switched
163     * to the provided locale. This influences only the behavior of the
164     * {@link org.opencms.staticexport.CmsLocalePrefixLinkSubstitutionHandler}.</p>
165     *
166     *
167     * Relative links are converted to absolute links, using the current element URI as base.<p>
168     *
169     * @param target the link that should be calculated, can be relative or absolute
170     * @param req the current request
171     * @param baseUri the base URI for the link source
172     * @param detailPage the target detail page, in case of linking to a specific detail page
173     * @param locale the locale for which the link should be created (see {@link org.opencms.staticexport.CmsLocalePrefixLinkSubstitutionHandler}
174     *
175     * @return the target link adjusted according to the web application path and the OpenCms static export rules
176     *
177     * @see #linkTagAction(String, ServletRequest)
178     *
179     * @since 8.0.3
180     */
181    public static String linkTagAction(
182        String target,
183        ServletRequest req,
184        String baseUri,
185        String detailPage,
186        Locale locale) {
187
188        CmsFlexController controller = CmsFlexController.getController(req);
189        // be sure the link is absolute
190        String uri = CmsLinkManager.getAbsoluteUri(target, controller.getCurrentRequest().getElementUri());
191        CmsObject cms = controller.getCmsObject();
192        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(baseUri) || (null != locale)) {
193            try {
194                cms = OpenCms.initCmsObject(cms);
195                if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(baseUri)) {
196                    cms.getRequestContext().setUri(baseUri);
197                }
198                if (null != locale) {
199                    cms.getRequestContext().setLocale(locale);
200                }
201            } catch (CmsException e) {
202                // should not happen, if it does we can't do anything useful and will just keep the original object
203                LOG.debug(e.getLocalizedMessage(), e);
204            }
205        }
206        // generate the link
207        return OpenCms.getLinkManager().substituteLinkForUnknownTarget(cms, uri, detailPage, false);
208    }
209
210    /**
211     * @see javax.servlet.jsp.tagext.Tag#doEndTag()
212     *
213     * @return EVAL_PAGE
214     *
215     * @throws JspException in case something goes wrong
216     */
217    @Override
218    public int doEndTag() throws JspException {
219
220        ServletRequest req = pageContext.getRequest();
221
222        // This will always be true if the page is called through OpenCms
223        if (CmsFlexController.isCmsRequest(req)) {
224            try {
225                // Get link-string from the body and reset body
226                String link = getBodyContent().getString();
227                getBodyContent().clear();
228                // Calculate the link substitution
229                String newlink = linkTagAction(link, req, getBaseUri(), getDetailPage(), m_locale);
230                // Write the result back to the page
231                getBodyContent().print(newlink);
232                getBodyContent().writeOut(pageContext.getOut());
233
234            } catch (Exception ex) {
235                if (LOG.isErrorEnabled()) {
236                    LOG.error(Messages.get().getBundle().key(Messages.ERR_PROCESS_TAG_1, "link"), ex);
237                }
238                throw new JspException(ex);
239            }
240        }
241        return EVAL_PAGE;
242    }
243
244    /**
245     * Returns the base URI used to create the link target.<p>
246     *
247     * @return  the base URI used to create the link target
248     */
249    public String getBaseUri() {
250
251        return m_baseUri;
252    }
253
254    /**
255     * Returns the target detail page path.<p>
256     *
257     * @return the target detail page path
258     */
259    public String getDetailPage() {
260
261        return m_detailPage;
262    }
263
264    /**
265     * @see javax.servlet.jsp.tagext.Tag#release()
266     */
267    @Override
268    public void release() {
269
270        super.release();
271    }
272
273    /**
274     * Sets the base URI used to create the link target.<p>
275     *
276     * @param baseUri the base URI used to create the link target
277     */
278    public void setBaseUri(String baseUri) {
279
280        m_baseUri = baseUri;
281    }
282
283    /**
284     * Sets the target detail page path.<p>
285     *
286     * @param detailPage the target detail page path
287     */
288    public void setDetailPage(String detailPage) {
289
290        m_detailPage = detailPage;
291    }
292
293    /**
294     * Sets the locale for the link to create.
295     *
296     * @param localeName name of the locale, e.g. "en", "en_US", ...
297     */
298    public void setLocale(String localeName) {
299
300        m_locale = CmsLocaleManager.getLocale(localeName);
301    }
302
303}