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, 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.json.JSONArray;
031import org.opencms.json.JSONException;
032import org.opencms.json.JSONObject;
033import org.opencms.jsp.util.CmsJspJsonWrapper;
034
035import javax.servlet.jsp.JspException;
036import javax.servlet.jsp.JspTagException;
037import javax.servlet.jsp.PageContext;
038import javax.servlet.jsp.tagext.BodyTagSupport;
039
040/**
041 * Abstract superclass that handles the common behavior of the jsonarray/jsonobject/jsonvalue tags.
042 *
043 * <p>Each of these tags constructs a JSON value, adds it to the surrounding JSON context object if one exists,
044 * and optionally stores the result in a page context variable, either as a JSON object or as formatted JSON text,
045 * depending on the value of the mode attribute.
046 */
047public abstract class A_CmsJspJsonTag extends BodyTagSupport {
048
049    /** JSON processing mode, decides what is stored in the variable given by var. */
050    enum Mode {
051        /** Store result of tag as an object. */
052        object,
053        /** Store result as wrapper object. */
054        wrapper,
055        /** Store result of tag as formatted JSON (i.e. a string) . */
056        text;
057    }
058
059    /** String describing request scope. */
060    private static final String SCOPE_REQUEST = "request";
061
062    /** String describing session scope. */
063    private static final String SCOPE_SESSION = "session";
064
065    /** String describing application scope. */
066    private static final String SCOPE_APPLICATION = "application";
067
068    /** Serial version id. */
069    private static final long serialVersionUID = -4536413263964718943L;
070
071    /** The key attribute. */
072    protected String m_key;
073
074    /** The mode attribute. */
075    protected String m_mode;
076
077    /** The var attribute. */
078    protected String m_var;
079
080    /** The target attribute. */
081    protected Object m_target;
082
083    /** The scope attribute. */
084    protected String m_scope;
085
086    /**
087     * Converts the given string description of a scope to the corresponding PageContext constant.
088     *
089     * @param scope String description of scope
090     *
091     * @return PageContext constant corresponding to given scope description
092     */
093    protected static int getScope(String scope) {
094
095        int ret = PageContext.PAGE_SCOPE; // default
096        if (SCOPE_REQUEST.equalsIgnoreCase(scope)) {
097            ret = PageContext.REQUEST_SCOPE;
098        } else if (SCOPE_SESSION.equalsIgnoreCase(scope)) {
099            ret = PageContext.SESSION_SCOPE;
100        } else if (SCOPE_APPLICATION.equalsIgnoreCase(scope)) {
101            ret = PageContext.APPLICATION_SCOPE;
102        }
103        return ret;
104    }
105
106    /**
107     * @see javax.servlet.jsp.tagext.TagSupport#doEndTag()
108     */
109    @Override
110    public int doEndTag() throws JspException {
111
112        if (m_var != null) {
113            // Export to a variable
114            String modeStr = m_mode;
115            Mode mode = Mode.wrapper;
116            int scopeValue = getScope(m_scope);
117            if (modeStr != null) {
118                try {
119                    mode = Mode.valueOf(modeStr);
120                } catch (Exception e) {
121                    throw new JspTagException("Unknown mode for json tag: " + modeStr);
122                }
123            }
124            Object val;
125            switch (mode) {
126                case object:
127                    val = getJsonValue();
128                    break;
129                case text:
130                    try {
131                        val = JSONObject.valueToString(getJsonValue());
132                    } catch (JSONException e) {
133                        throw new JspTagException("Could not format JSON", e);
134                    }
135                    break;
136                case wrapper:
137                default:
138                    val = new CmsJspJsonWrapper(getJsonValue());
139                    break;
140            }
141            pageContext.setAttribute(m_var, val, scopeValue);
142        } else if (m_target != null) {
143            // Export to a specified JSON object
144            addToTarget(m_target, getJsonValue(), m_key);
145        } else {
146            I_CmsJspJsonContext context = (I_CmsJspJsonContext)findAncestorWithClass(this, I_CmsJspJsonContext.class);
147            if (context != null) {
148                context.addValue(m_key, getJsonValue());
149            }
150        }
151        return EVAL_PAGE;
152    }
153
154    /**
155     * Returns the JSON value that should be added to the surrounding context and/or stored in the variable
156     * given by the var attribute.
157     *
158     * @return the value to add/store
159     * @throws JspTagException if getting the value fails
160     */
161    public abstract Object getJsonValue() throws JspTagException;
162
163    /**
164     * Releases the resources used by this tag.<p>
165     */
166    @Override
167    public void release() {
168
169        init();
170        super.release();
171    }
172
173    /**
174     * Sets the key attribute.
175     *
176     * @param key the key under which to store the value in the surrounding JSON object
177     */
178    public void setKey(String key) {
179
180        m_key = key;
181    }
182
183    /**
184     * Sets the mode attribute.
185     *
186     * @param mode the mode
187     */
188    public void setMode(String mode) {
189
190        m_mode = mode;
191    }
192
193    /**
194     * Sets the scope attribute.
195     *
196     * @param scope the variable scope
197     */
198    public void setScope(String scope) {
199
200        m_scope = scope;
201    }
202
203    /**
204     * Sets the target attribute.
205     *
206     * @param target the target Object to store the JSON in.
207     *
208     * This must be another JSON object or a JSON wrapper.
209     */
210    public void setTarget(Object target) {
211
212        m_target = target;
213    }
214
215    /**
216     * Sets the var attribute.
217     *
218     * @param var the name of the variable to store the result in
219     */
220    public void setVar(String var) {
221
222        m_var = var;
223    }
224
225    /**
226     * Adds the specified value to the selected target.<p>
227     *
228     * @param target the target object
229     * @param val the value to set
230     * @param key the key to set the value, required in case the target is a JSONObject
231     *
232     * @throws JspException in case the value could not be added to the target
233     */
234    protected void addToTarget(Object target, Object val, String key) throws JspException {
235
236        if (target instanceof JSONObject) {
237            if (key == null) {
238                throw new JspTagException("Can not add to JSONObject target with no key (val:" + val + ")");
239            }
240            try {
241                JSONObject jsonObj = (JSONObject)target;
242                if (jsonObj.has(key)) {
243                    jsonObj.append(key, val);
244                } else {
245                    jsonObj.put(key, val);
246                }
247            } catch (JSONException e) {
248                throw new JspTagException("Could not add value to JSONObject target", e);
249            }
250        } else if (target instanceof JSONArray) {
251            ((JSONArray)target).put(val);
252        } else if (target instanceof CmsJspJsonWrapper) {
253            Object wrappedTaget = ((CmsJspJsonWrapper)target).getObject();
254            addToTarget(wrappedTaget, val, key);
255        } else {
256            throw new JspTagException("Invalid target specified (target:" + val + ")");
257        }
258    }
259
260    /**
261     * Initializes / resets the internal values.<p>
262     */
263    protected void init() {
264
265        m_key = null;
266        m_var = null;
267        m_mode = null;
268        m_target = null;
269        m_scope = null;
270    }
271}