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.file.CmsPropertyDefinition;
032import org.opencms.file.CmsResource;
033import org.opencms.flex.CmsFlexController;
034import org.opencms.i18n.CmsMessageContainer;
035import org.opencms.jsp.util.CmsJspStandardContextBean;
036import org.opencms.main.CmsException;
037import org.opencms.main.CmsLog;
038import org.opencms.main.OpenCms;
039import org.opencms.util.CmsStringUtil;
040import org.opencms.xml.content.CmsXmlContent;
041import org.opencms.xml.content.CmsXmlContentFactory;
042
043import java.util.Arrays;
044import java.util.List;
045
046import javax.servlet.ServletRequest;
047import javax.servlet.http.HttpServletRequest;
048import javax.servlet.jsp.JspException;
049import javax.servlet.jsp.tagext.TagSupport;
050
051import org.apache.commons.logging.Log;
052
053/**
054 * Provides access to OpenCms and System related information.<p>
055 *
056 * This tag supports the following special "property" values:
057 * <ul>
058 * <li><code>opencms.version</code> returns the current OpenCms version, e.g. <i>8.0.0</i>.
059 * <li><code>opencms.url</code> returns the current request URL, e.g.
060 * <i>http://localhost:8080/opencms/opencms/index.jsp</i>.
061 * <li><code>opencms.uri</code> returns the current request URI, e.g.
062 * <i>/opencms/opencms/index.jsp</i>.
063 * <li><code>opencms.webapp</code> returns the name of the OpenCms web application, e.g.
064 * <i>opencms</i>.
065 * <li><code>opencms.webbasepath</code> returns the name of system path to the OpenCms web
066 * application, e.g. <i>C:\Java\Tomcat\webapps\opencms\</i>.
067 * <li><code>opencms.request.uri</code> returns the name of the currently requested URI in
068 * the OpenCms VFS, e.g. <i>/index.jsp</i>.
069 * <li><code>opencms.request.element.uri</code> returns the name of the currently processed element,
070 * which might be a sub-element like a template part,
071 * in the OpenCms VFS, e.g. <i>/system/modules/org.opencms.welcome/jsptemplates/welcome.jsp</i>.
072 * <li><code>opencms.request.folder</code> returns the name of the parent folder of the currently
073 * requested URI in the OpenCms VFS, e.g. <i>/</i>.
074 * <li><code>opencms.request.encoding</code> returns the content encoding that has been set
075 * for the currently requested resource, e.g. <i>ISO-8859-1</i>.
076 * <li><code>opencms.title</code> (since 8.0.0) returns the title of the document that should be used for the
077 * HTML title tag. This is useful for container detail pages, in which case it will return the Title
078 * of the detail, not the container page. Otherwise it just returns the value of the Title property.
079 * <li><code>opencms.description</code> (since 9.0.1)
080 * <li><code>opencms.keywords</code> (since 9.0.1)
081 * </ul>
082 *
083 * All other property values that are passes to the tag as routed to a standard
084 * <code>System.getProperty(value)</code> call,
085 * so you can also get information about the Java VM environment,
086 * using values like <code>java.vm.version</code> or <code>os.name</code>.<p>
087 *
088 * If the given property value does not match a key from the special OpenCms values
089 * and also not the system values, a (String) message is returned with a formatted
090 * error message.<p>
091 *
092 * @since 6.0.0
093 */
094public class CmsJspTagInfo extends TagSupport {
095
096    /** The log object for this class. */
097    private static final Log LOG = CmsLog.getLog(CmsJspTagInfo.class);
098
099    /** Serial version UID required for safe serialization. */
100    private static final long serialVersionUID = -3881095296148023924L;
101
102    /** Static array with allowed info property values. */
103    private static final String[] SYSTEM_PROPERTIES = {
104        "opencms.version", // 0
105        "opencms.url", // 1
106        "opencms.uri", // 2
107        "opencms.webapp", // 3
108        "opencms.webbasepath", // 4
109        "opencms.request.uri", // 5
110        "opencms.request.element.uri", // 6
111        "opencms.request.folder", // 7
112        "opencms.request.encoding", // 8
113        "opencms.request.locale", // 9
114        "opencms.title", // 10
115        "opencms.description", // 11
116        "opencms.keywords" // 12
117    };
118
119    /** Array list of allowed property values for more convenient lookup. */
120    private static final List<String> SYSTEM_PROPERTIES_LIST = Arrays.asList(SYSTEM_PROPERTIES);
121
122    /** The value of the <code>property</code> attribute. */
123    private String m_property;
124
125    /**
126     * Returns the description of a page delivered from OpenCms, usually used for the <code>description</code> metatag of
127     * a HTML page.<p>
128     *
129     * If no description information has been found, the empty String "" is returned.<p>
130     *
131     * @param controller the current OpenCms request controller
132     * @param req the current request
133     *
134     * @return the description of a page delivered from OpenCms
135     */
136    public static String getDescriptionInfo(CmsFlexController controller, HttpServletRequest req) {
137
138        String result = null;
139        CmsObject cms = controller.getCmsObject();
140
141        try {
142
143            CmsJspStandardContextBean contextBean = CmsJspStandardContextBean.getInstance(req);
144            if (contextBean.isDetailRequest()) {
145                // this is a request to a detail page
146                CmsResource res = contextBean.getDetailContent();
147                // read the description of the detail resource as fall back (may contain mapping from another locale)
148                result = cms.readPropertyObject(res, CmsPropertyDefinition.PROPERTY_DESCRIPTION, false).getValue();
149            }
150            if (result == null) {
151                // read the title of the requested resource as fall back
152                result = cms.readPropertyObject(
153                    cms.getRequestContext().getUri(),
154                    CmsPropertyDefinition.PROPERTY_DESCRIPTION,
155                    true).getValue();
156            }
157        } catch (CmsException e) {
158            // NOOP, result will be null
159        }
160        if (CmsStringUtil.isEmptyOrWhitespaceOnly(result)) {
161            result = "";
162        }
163
164        return result;
165    }
166
167    /**
168     * Returns the keywords of a page delivered from OpenCms, usually used for the <code>keywords</code> metatag of
169     * a HTML page.<p>
170     *
171     * If no description information has been found, the empty String "" is returned.<p>
172     *
173     * @param controller the current OpenCms request controller
174     * @param req the current request
175     *
176     * @return the description of a page delivered from OpenCms
177     */
178    public static String getKeywordsInfo(CmsFlexController controller, HttpServletRequest req) {
179
180        String result = null;
181        CmsObject cms = controller.getCmsObject();
182
183        try {
184
185            CmsJspStandardContextBean contextBean = CmsJspStandardContextBean.getInstance(req);
186            if (contextBean.isDetailRequest()) {
187                // this is a request to a detail page
188                CmsResource res = contextBean.getDetailContent();
189                // read the keywords of the detail resource as fall back (may contain mapping from another locale)
190                result = cms.readPropertyObject(res, CmsPropertyDefinition.PROPERTY_KEYWORDS, false).getValue();
191            }
192            if (result == null) {
193                // read the title of the requested resource as fall back
194                result = cms.readPropertyObject(
195                    cms.getRequestContext().getUri(),
196                    CmsPropertyDefinition.PROPERTY_KEYWORDS,
197                    true).getValue();
198            }
199        } catch (CmsException e) {
200            // NOOP, result will be null
201        }
202        if (CmsStringUtil.isEmptyOrWhitespaceOnly(result)) {
203            result = "";
204        }
205
206        return result;
207    }
208
209    /**
210     * Returns the title of a page delivered from OpenCms, usually used for the <code>&lt;title&gt;</code> tag of
211     * a HTML page.<p>
212     *
213     * If no title information has been found, the empty String "" is returned.<p>
214     *
215     * @param controller the current OpenCms request controller
216     * @param req the current request
217     *
218     * @return the title of a page delivered from OpenCms
219     */
220    public static String getTitleInfo(CmsFlexController controller, HttpServletRequest req) {
221
222        String result = null;
223        CmsObject cms = controller.getCmsObject();
224
225        try {
226
227            CmsJspStandardContextBean contextBean = CmsJspStandardContextBean.getInstance(req);
228            if (contextBean.isDetailRequest()) {
229                // this is a request to a detail page
230                CmsResource res = contextBean.getDetailContent();
231                CmsXmlContent content = CmsXmlContentFactory.unmarshal(cms, res, req);
232                result = content.getHandler().getTitleMapping(cms, content, cms.getRequestContext().getLocale());
233                if (result == null) {
234                    // title not found, maybe no mapping OR not available in the current locale
235                    // read the title of the detail resource as fall back (may contain mapping from another locale)
236                    result = cms.readPropertyObject(res, CmsPropertyDefinition.PROPERTY_TITLE, false).getValue();
237                }
238            }
239            if (result == null) {
240                // read the title of the requested resource as fall back
241                result = cms.readPropertyObject(
242                    cms.getRequestContext().getUri(),
243                    CmsPropertyDefinition.PROPERTY_TITLE,
244                    true).getValue();
245            }
246        } catch (CmsException e) {
247            // NOOP, result will be null
248        }
249        if (CmsStringUtil.isEmptyOrWhitespaceOnly(result)) {
250            result = "";
251        }
252
253        return result;
254    }
255
256    /**
257     * Returns the selected info property value based on the provided
258     * parameters.<p>
259     *
260     * @param property the info property to look up
261     * @param req the currents request
262     * @return the looked up property value
263     */
264    public static String infoTagAction(String property, HttpServletRequest req) {
265
266        if (property == null) {
267            CmsMessageContainer errMsgContainer = Messages.get().container(Messages.GUI_ERR_INVALID_INFO_PROP_0);
268            return Messages.getLocalizedMessage(errMsgContainer, req);
269        }
270        CmsFlexController controller = CmsFlexController.getController(req);
271
272        String result = null;
273        switch (SYSTEM_PROPERTIES_LIST.indexOf(property)) {
274            case 0: // opencms.version
275                result = OpenCms.getSystemInfo().getVersionNumber();
276                break;
277            case 1: // opencms.url
278                result = req.getRequestURL().toString();
279                break;
280            case 2: // opencms.uri
281                result = req.getRequestURI();
282                break;
283            case 3: // opencms.webapp
284                result = OpenCms.getSystemInfo().getWebApplicationName();
285                break;
286            case 4: // opencms.webbasepath
287                result = OpenCms.getSystemInfo().getWebApplicationRfsPath();
288                break;
289            case 5: // opencms.request.uri
290                result = controller.getCmsObject().getRequestContext().getUri();
291                break;
292            case 6: // opencms.request.element.uri
293                result = controller.getCurrentRequest().getElementUri();
294                break;
295            case 7: // opencms.request.folder
296                result = CmsResource.getParentFolder(controller.getCmsObject().getRequestContext().getUri());
297                break;
298            case 8: // opencms.request.encoding
299                result = controller.getCmsObject().getRequestContext().getEncoding();
300                break;
301            case 9: // opencms.request.locale
302                result = controller.getCmsObject().getRequestContext().getLocale().toString();
303                break;
304            case 10: // opencms.title
305                result = getTitleInfo(controller, req);
306                break;
307            case 11: // opencms.description
308                result = getDescriptionInfo(controller, req);
309                break;
310            case 12: // opencms.keywords
311                result = getKeywordsInfo(controller, req);
312                break;
313            default:
314                result = System.getProperty(property);
315                if (result == null) {
316                    CmsMessageContainer errMsgContainer = Messages.get().container(
317                        Messages.GUI_ERR_INVALID_INFO_PROP_1,
318                        property);
319                    return Messages.getLocalizedMessage(errMsgContainer, req);
320                }
321        }
322
323        return result;
324    }
325
326    /**
327     * @see javax.servlet.jsp.tagext.Tag#doStartTag()
328     */
329    @Override
330    public int doStartTag() throws JspException {
331
332        ServletRequest req = pageContext.getRequest();
333
334        // This will always be true if the page is called through OpenCms
335        if (CmsFlexController.isCmsRequest(req)) {
336
337            try {
338                String result = infoTagAction(m_property, (HttpServletRequest)req);
339                // Return value of selected property
340                pageContext.getOut().print(result);
341            } catch (Exception ex) {
342                if (LOG.isErrorEnabled()) {
343                    LOG.error(Messages.get().getBundle().key(Messages.ERR_PROCESS_TAG_1, "info"), ex);
344                }
345                throw new JspException(ex);
346            }
347        }
348        return SKIP_BODY;
349    }
350
351    /**
352     * Returns the selected info property.<p>
353     *
354     * @return the selected info property
355     */
356    public String getProperty() {
357
358        return m_property != null ? m_property : "";
359    }
360
361    /**
362     * @see javax.servlet.jsp.tagext.Tag#release()
363     */
364    @Override
365    public void release() {
366
367        super.release();
368        m_property = null;
369    }
370
371    /**
372     * Sets the info property name.<p>
373     *
374     * @param name the info property name to set
375     */
376    public void setProperty(String name) {
377
378        if (name != null) {
379            m_property = name.toLowerCase();
380        }
381    }
382
383}