/*******************************************************************************
* Copyright 2009, 2010 Innovation Gate GmbH. All Rights Reserved.
*
* This file is part of the OpenWGA server platform.
*
* OpenWGA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, a special exception is granted by the copyright holders
* of OpenWGA called "OpenWGA plugin exception". You should have received
* a copy of this exception along with OpenWGA in file COPYING.
* If not, see <http://www.openwga.com/gpl-plugin-exception>.
*
* OpenWGA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenWGA in file COPYING.
* If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package de.innovationgate.wgpublisher.webtml;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadException;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import de.innovationgate.utils.Base64;
import de.innovationgate.utils.WGUtils;
import de.innovationgate.utils.XStreamUtils;
import de.innovationgate.utils.Zipper;
import de.innovationgate.webgate.api.WGAPIException;
import de.innovationgate.webgate.api.WGContent;
import de.innovationgate.wgpublisher.WGACore;
import de.innovationgate.wgpublisher.WGPDispatcher;
import de.innovationgate.wgpublisher.WGPRequestPath;
import de.innovationgate.wgpublisher.expressions.ExpressionResult;
import de.innovationgate.wgpublisher.webtml.utils.AjaxInfo;
import de.innovationgate.wgpublisher.webtml.utils.FormInfo;
import de.innovationgate.wgpublisher.webtml.utils.RootTagReceptor;
import de.innovationgate.wgpublisher.webtml.utils.TMLAction;
import de.innovationgate.wgpublisher.webtml.utils.TMLActionException;
import de.innovationgate.wgpublisher.webtml.utils.TMLActionLink;
import de.innovationgate.wgpublisher.webtml.utils.TMLContext;
import de.innovationgate.wgpublisher.webtml.utils.TMLException;
import de.innovationgate.wgpublisher.webtml.utils.TMLForm;
import de.innovationgate.wgpublisher.webtml.utils.TMLInvalidActionLinkException;
import de.innovationgate.wgpublisher.webtml.utils.TMLOption;
import de.innovationgate.wgpublisher.webtml.utils.TMLPortlet;
import de.innovationgate.wgpublisher.webtml.utils.TMLOptionPreserver;
import de.innovationgate.wgpublisher.webtml.utils.URLBuilder;
import de.innovationgate.wgpublisher.webtml.utils.VarParamsMap;
public class Root extends Base {
public static final String URLPARAM_ACTION = "$action";
public static final String REQUEST_ATTRIB_IS_AJAX_SUBFORM = "de.innovationgate.request.attrib.isAjaxSubForm";
// Collects all options that should not be recovered in AJAX requests
private static final Set UNRECOVERABLE_OPTIONS = new HashSet();
public static final String URLPARAM_VARS = "$vars";
static {
UNRECOVERABLE_OPTIONS.add(Base.OPTION_PORTLET_EVENT_STARTINDEX);
UNRECOVERABLE_OPTIONS.add(Base.OPTION_DESIGNDB);
UNRECOVERABLE_OPTIONS.add(Base.OPTION_TMLMODULE_NAME);
UNRECOVERABLE_OPTIONS.add(Base.OPTION_TMLMODULE_MEDIAKEY);
}
/**
* @see Base#tmlStartTag()
*/
private String resource = null;
private String ref = null;
private String modulename = null;
private String modulemediakey = null;
public static class Status extends BaseTagStatus {
private Boolean _tagPoolingEnabled = null;
private boolean _ajax;
private AjaxInfo _ajaxInfo;
private boolean _isAjaxNoRefreshCall = false;
private RootTagReceptor receptorTag = null;
public String resource;
private String _upperTml;
}
@Override
public BaseTagStatus createTagStatus() {
return new Status();
}
public void tmlStartTag() throws TMLException, WGAPIException {
Status status = (Status) getStatus();
status.resource = getResource();
status.keepResult = true;
// Set module info
status.setOption(OPTION_TMLMODULE_NAME, getModulename(), null);
status.setOption(OPTION_TMLMODULE_MEDIAKEY, getModulemediakey(), null);
status.receptorTag = (RootTagReceptor) this.getParentTag();
HttpServletRequest request = (HttpServletRequest) this.pageContext.getRequest();
storeCurrentTMLAttributes(request);
// Root tag was included by another tag
if (status.receptorTag != null) {
processIncludedRoot();
}
// Root tag is absolute root tag of this request - do basic functionalities
else {
processAbsoluteRoot(request);
}
}
private void processIncludedRoot() throws TMLException {
Status status = (Status) getStatus();
this.setTMLContext(status.receptorTag.getChildTagContext());
this.setChildTagContext(status.receptorTag.getChildTagContext());
status.receptorTag.setRootTagStatus((Status) getStatus());
// Test for inclusion depth. Evaluation will stop, if level 32 reached for stability reasons (stack overflow)
Integer includeLevel = (Integer) getTMLContext().option(WGACore.ATTRIB_INCLUDELEVEL);
if (includeLevel.intValue() >= 32) {
throw new TMLException("Maximum tml:include level of 32 reached. No further inclusions allowed.", true);
}
else {
status.setOption(WGACore.ATTRIB_INCLUDELEVEL, new Integer(includeLevel.intValue() + 1), null);
}
// Filter out local options
if (status.receptorTag instanceof Include.Status) {
Include.Status includeTag = (Include.Status) status.receptorTag;
filterOptions(includeTag.getOptionsToFilter());
}
}
private void processAbsoluteRoot(HttpServletRequest request) throws WGAPIException {
Status status = (Status) getStatus();
// check if appserver has enabled tag pooling
// if not the property _tagPoolingEnabled must be everytime null
if (status._tagPoolingEnabled == null) {
status._tagPoolingEnabled = new Boolean(true);
} else {
if (status._tagPoolingEnabled.booleanValue()) {
// appserver has enabled tagpooling
String message = "Your appserver has enabled JSP-Tag-Pooling. Good so!.";
this.addWarning(message);
log.warn(message);
}
}
// check for ajaxCall
status._ajax = false;
status._ajaxInfo = (AjaxInfo) request.getAttribute(WGACore.ATTRIB_AJAXINFO);
if ( status._ajaxInfo != null) {
status._ajax = true;
// restore ajax environment
this.restoreEnvironmentFromAjaxCall(status._ajaxInfo, request);
}
// set currentMediakey to MainMediaKey
status.setOption(OPTION_CURRENT_MEDIAKEY, getStatus().getMainMediaKey(), null);
// Set basic request attributes
status.parentTag = status;
setBasicRequestAttributes(request);
// Eventually enable TML Debug
HttpSession session = this.pageContext.getSession();
Boolean tmlDebug = (Boolean) session.getAttribute(WGACore.ATTRIB_TMLDEBUG);
if (tmlDebug != null && tmlDebug.booleanValue() == true) {
enableDebug(session);
}
// Determine, which (if any) document can be edited in this request
if (status.isBrowserInterface()) {
WGContent content = this.getTMLContext().content();
List userNamesList = new ArrayList();
userNamesList.add(content.getAuthor());
if ( content.getStatus().equals(WGContent.STATUS_DRAFT)
&& (!content.hasCompleteRelationships() || content.getStructEntry().mayEditEntryAndContent() == null)
&& content.getLanguage().mayCreateContent()
&& content.getDatabase().isMemberOfUserList( userNamesList )
&& !content.hasItem("remote_info")
) {
pageContext.getRequest().setAttribute(WGACore.ATTRIB_EDITDOCUMENT, content.getContentKey().toString());
}
}
// process multipartformdata
List data = null;
// first try to retrieve formdata from ajax call
String ajaxFormdataSessionKey = request.getParameter("$ajaxformkey");
if (ajaxFormdataSessionKey != null && !ajaxFormdataSessionKey.trim().equals("")) {
data = (List) request.getSession().getAttribute(ajaxFormdataSessionKey);
if (data == null) {
this.getTMLContext().addwarning("Could not restore ajaxformdata. FormKey found but nothing in session.", true);
} else {
// remove session attribute
request.getSession().removeAttribute(ajaxFormdataSessionKey);
}
} else {
// try to retrieve from current post-request
data = retrieveMultipartFormData(request);
}
// create TMLForm if data is available
TMLForm form = null;
if (data != null) {
// F00004936
// check if this request contains a tmlform ($forminfo is present)
// otherwise this is an standard multipart request and multipartData will be transported
// as raw data within the tmlvar "multipartData"
boolean isTMLForm = false;
Iterator multipartItems = data.iterator();
while (multipartItems.hasNext()) {
FileItem fi = (FileItem) multipartItems.next();
if (fi.getFieldName().equals("$forminfo")) {
isTMLForm = true;
}
}
if (isTMLForm) {
//create a tml form object
form = processTMLForm(request, data);
} else {
// put multipartdata in request for custom processing
// used by CM for multi file uploads
getTMLContext().setvar("multipartData", data);
}
}
// Process WebTML var parameters
String varParam = request.getParameter(URLPARAM_VARS);
if (varParam != null) {
try {
processVarParams(varParam);
}
catch (Exception e) {
log.error("Exception processing var params", e);
addWarning("Unable to process var params: " + e.getMessage());
}
}
// eventually execute action
boolean actioncalled = false;
try {
actioncalled = processAction(request, form, status._ajax);
}
catch (Exception e) {
log.error("Exception processing WebTML action", e);
addWarning("Unable to process WebTML action: " + e.getMessage());
}
// if an action was called
if (actioncalled) {
// if keepOnValidate is true and form was validated once and form was not validated
// in this request
if (form != null) {
FormInfo formInfo = form.getforminfo();
if (formInfo.isValidated() && formInfo.keepOnValidate() && !form.wasValidatedInThisRequest()) {
form.validate();
}
}
}
if (status._ajax) {
// if session is new throw corresponding system event
if (getTMLContext().getrequest().getSession().isNew()) {
fireSessionIsNewPortletEvent();
} else {
// check if session was new - this might happen on ajax calls with form data
// this session attribute is set in Dispatcher on ajax form call
String ajaxSessionWasNewFlagSessionKey = request.getParameter("$ajaxformkey") + ".event.SessionWasNew";
Boolean sessionWasNew = (Boolean) request.getSession().getAttribute(ajaxSessionWasNewFlagSessionKey);
if (sessionWasNew != null && sessionWasNew.booleanValue()) {
// remove attribute
request.getSession().removeAttribute(ajaxSessionWasNewFlagSessionKey);
// fire session is new event
fireSessionIsNewPortletEvent();
}
}
if (getTMLContext().getportlet() != null) {
String portletKey = status._ajaxInfo.getId();
// register portlet on client side - this must be done here to ensure registration is also done after an ajaxcall
String javaScriptPRegistration = null;
if (status._isAjaxNoRefreshCall) {
// this is an no refresh ajax call - portlet registration is not necessary
//javaScriptPRegistration = getTMLContext().createJavaScriptPortletRegistration(portletKey, true);
} else {
javaScriptPRegistration = getTMLContext().createJavaScriptPortletRegistration(portletKey, false);
}
if (javaScriptPRegistration != null) {
this.setPrefix(this.getPrefix() + javaScriptPRegistration);
}
// Prepare for serverside portlet event processing inside the currently rendered portlet
getTMLContext().getportlet().prepareEventProcessing(this);
}
}
}
private void processVarParams(String varParam) throws WGAPIException, UnsupportedEncodingException, IOException {
VarParamsMap varParams = URLBuilder.extractVarParameters(varParam, getTMLContext().getwgacore().getDesEncrypter());
// Wrong session? Discard var params
if (!varParams.isValidSession(getPageContext().getSession())) {
getTMLContext().getlog().warn("Var params for wrong session used by client " + getPageContext().getRequest().getRemoteAddr() + ". Not used.");
return;
}
getTMLContext().getrequest().setAttribute(WGACore.ATTRIB_VAR_PARAMETERS, varParams);
for (Map.Entry<String,Object> param : varParams.entrySet()) {
getTMLContext().setvar(param.getKey(), param.getValue());
}
}
private void fireSessionIsNewPortletEvent() throws WGAPIException {
TMLPortlet portlet = getTMLContext().getportlet();
if (portlet != null) {
portlet.fireevent(de.innovationgate.wgpublisher.webtml.utils.PortletEvent.SESSION_IS_NEW_EVENT);
} else {
String sessionIsNewEvent = de.innovationgate.wgpublisher.webtml.utils.PortletEvent.SESSION_IS_NEW_EVENT.toJavaScriptObject();
String encodedEvent = Base64.encodeWeb(sessionIsNewEvent.getBytes());
try {
getTMLContext().redirectto(getTMLContext().getrequest().getContextPath() + "/fireSystemEvent.jsp?event=" + encodedEvent);
}
catch (IOException e) {
getTMLContext().addwarning("Unable to fire portlet event 'session is new'. Redirect to 'fireSystemEvent.jsp' failed bc. of exception '" + e.getMessage() + "'");
}
}
}
private void enableDebug(HttpSession session) {
Document doc = DocumentHelper.createDocument();
Element rootElement = doc.addElement("tmldebugdocument");
rootElement.addAttribute("url", WGUtils.reduce(getStatus().getRequestURL(), 100));
rootElement.addAttribute("started", DEBUG_TIMESTAMP_FORMAT.format(new Date()));
rootElement.addAttribute("traceresults", String.valueOf(session.getAttribute(WGACore.ATTRIB_TMLDEBUG_TRACE_RESULTS)));
rootElement.addAttribute("traceoptions", String.valueOf(session.getAttribute(WGACore.ATTRIB_TMLDEBUG_TRACE_OPTIONS)));
List debugDocuments = WGACore.getDebugDocumentsList(session);
debugDocuments.add(doc);
createDebugNode(rootElement);
try {
debugNode.addAttribute("context", getTMLContext().getpath());
}
catch (WGAPIException e) {
debugNode.addAttribute("context", "Unable to retrieve contextpath bc. of exception: " + e.getClass().getName() + " message: " + e.getMessage());
}
}
private void setBasicRequestAttributes(HttpServletRequest request) {
Status status = (Status) getStatus();
request.setAttribute(WGACore.ATTRIB_ROOT_TAG, status);
request.setAttribute(WGACore.ATTRIB_REQUESTTIME, new Long(System.currentTimeMillis()));
status.setOption(WGACore.ATTRIB_INCLUDELEVEL, new Integer(0), null);
status.setOption(WGACore.ATTRIB_ITEM_MAPPINGS, new java.util.HashMap(), null);
status.setOption(WGACore.ATTRIB_META_MAPPINGS, new java.util.HashMap(), null);
if (status._ajaxInfo == null) {
// if this is an static tml request we use a dummy designdbkey
String requestType = (String) request.getAttribute(WGACore.ATTRIB_REQUESTTYPE);
if(requestType != null && requestType.equals(WGPDispatcher.REQUESTTYPE_STATICTML)) {
status.setOption(OPTION_DESIGNDB, WGACore.STATICTML_DESIGNDBKEY, null);
}
else {
status.setOption(OPTION_DESIGNDB, getTMLContext().db().getDbReference(), null);
}
}
// Set DefaultURLBuilder if no other is already set
getTMLContext().getwgacore().retrieveURLBuilder(request, getTMLContext().db());
}
private List retrieveMultipartFormData(HttpServletRequest request) {
if (FileUpload.isMultipartContent(request) && request.getContentLength() != -1) {
DiskFileUpload dfu = new DiskFileUpload();
//F000037B2
if (getCore().getCharacterEncoding() != null) {
dfu.setHeaderEncoding(getCore().getCharacterEncoding());
}
try {
List fileItems = dfu.parseRequest(request);
return fileItems;
} catch (FileUploadException e) {
getCore().getLog().error("Error parsing multipart form", e);
return null;
}
} else {
return null;
}
}
private TMLForm processTMLForm(HttpServletRequest request, List multipartData) {
Status status = (Status) getStatus();
TMLForm form = null;
try {
form = new TMLForm(multipartData, this.getTMLContext(), this.getCore().getLog(), request);
} catch (TMLException e) {
this.getTMLContext().addwarning("Error creating TMLForm object bc. of exception: " + e.getClass().getName() + " message: " + e.getMessage(), true);
return null;
} catch (WGAPIException e) {
this.getTMLContext().addwarning("Error creating TMLForm object bc. of exception: " + e.getClass().getName() + " message: " + e.getMessage(), true);
return null;
} catch (UnsupportedEncodingException e) {
this.getTMLContext().addwarning("Error creating TMLForm object bc. of exception: " + e.getClass().getName() + " message: " + e.getMessage() + " - ensure that you have configured a valid 'characterEncoding'", true);
return null;
}
// Eventually merge with persistent form
TMLForm persistentForm = (TMLForm) getTMLContext().getPersistentForms().get(form.getformid());
if (persistentForm != null) {
persistentForm.importForm(form);
form = persistentForm;
}
else {
getTMLContext().registerForm(form, false);
}
request.setAttribute(WGACore.ATTRIB_LASTFORM, form);
if (form != null) {
// reset validated in this request flag
form.setWasValidatedInThisRequest(false);
}
// Look if the form is our "superform". If so we switch to AJAX subform mode.
if (status._ajaxInfo != null && status._ajaxInfo.getSuperform() != null && status._ajaxInfo.getSuperform().equals(form.getformid())) {
getPageContext().getRequest().setAttribute(Root.REQUEST_ATTRIB_IS_AJAX_SUBFORM, Boolean.TRUE);
}
return form;
}
private boolean processAction(HttpServletRequest request, TMLForm form, boolean ajax) {
Status status = (Status) getStatus();
boolean actioncalled = false;
// Location of Actionkey depends. When form available, then is located in form, else is URL parameter
String actionKey = null;
if (form != null) {
actionKey = form.getformaction();
}
else {
actionKey = request.getParameter(URLPARAM_ACTION);
}
// Parse the action link and call the action
TMLActionLink actionLink;
if (actionKey != null && !actionKey.trim().equals("")) {
// actions
try {
actionLink = new TMLActionLink(URLDecoder.decode(actionKey, "UTF-8"),getCore());
long starttime = System.currentTimeMillis();
TMLAction action = callAction(actionLink, ajax);
long endtime = System.currentTimeMillis();
// We rebuild the session on the current context if the action was a master action
// to be able to pick up modifications done there (F00004096)
if (action != null && action.isMaster()) {
getTMLContext().db().reopenSession();
}
//F00004242
if (actionLink.getMode() != null && actionLink.getMode().equals(TMLActionLink.MODE_AJAX_NO_PORTLET_REFRESH)) {
// this is an ajax action call do not render content result but portletEvents
status._isAjaxNoRefreshCall = true;
appendResult("");
setEvalBody(false);
}
actioncalled = true;
if (debugNode != null) {
debugNode.addAttribute("actiontime", new Long(endtime - starttime).toString());
}
}
catch (TMLInvalidActionLinkException e) {
// Not logging these
}
catch (TMLActionException e) {
addWarning("Error calling TML action: " + e.getMessage());
}
catch (IOException e) {
addWarning("Error decoding action link: " + e.getMessage());
}
catch (WGAPIException e) {
addWarning("Error calling TML action: " + e.getMessage());
}
}
// Conditionally execute special action changeLanguage
WGPRequestPath path = (WGPRequestPath) request.getAttribute(WGACore.ATTRIB_REQUESTPATH);
if (path.getPreferredLanguageChange() != null) {
actionLink = new TMLActionLink(request.getSession());
actionLink.setDefaultAction(TMLAction.DEFAULTACTION_CHANGELANGUAGE);
try {
if (path.getPreferredLanguageChange().equals(WGPRequestPath.PREFERREDLANGUAGECHANGE_USECONTENT)) {
actionLink.setParam1((String) getTMLContext().meta("language"));
}
else {
actionLink.setParam1(path.getPreferredLanguageChange());
}
actionLink.setContextPath(getTMLContext().getpath());
TMLAction calledAction = callAction(actionLink, ajax);
// In case of a called master action we rebuild the session of the current db
// To let the following WebTML request reflect eventually done changes in the action
if (calledAction != null && calledAction.isMaster()) {
getTMLContext().db().reopenSession();
}
}
catch (TMLActionException e) {
addWarning("Error changing preferred language to '" + path.getPreferredLanguageChange() + "' bc of exception: " + e.getClass().getName() + " message: " + e.getMessage());
log.error("Error changing preferred language to '" + path.getPreferredLanguageChange() + "'", e);
}
catch (WGAPIException e) {
addWarning("Error changing preferred language to '" + path.getPreferredLanguageChange() + "' bc of exception: " + e.getClass().getName() + " message: " + e.getMessage());
log.error("Error changing preferred language to '" + path.getPreferredLanguageChange() + "'", e);
}
actioncalled = true;
}
try {
if (getTMLContext().getportlet() != null && getTMLContext().getportlet().getcontext() != null) {
setChildTagContext(getTMLContext().getportlet().getcontext());
}
} catch (WGAPIException e) {
addWarning("Error setting portlet context bc of exception: " + e.getClass().getName() + " message: " + e.getMessage());
log.error("Error setting portlet context", e);
}
return actioncalled;
}
/**
* @throws WGAPIException
* @see Base#tmlEndTag()
*/
public void tmlEndTag() throws TMLException, WGAPIException {
Status status = (Status) getStatus();
// check for portlet events that were issued inside the AJAX call and render if present
// this must be done here to ensure these events are executed as javascript by the ajaxcall-function
if (status._ajax == true) {
String javaScriptPEvents = null;
if (status._isAjaxNoRefreshCall) {
javaScriptPEvents = getTMLContext().createJavaScriptPortletEvents(status._ajaxInfo.getId(), true);
} else {
javaScriptPEvents = getTMLContext().createJavaScriptPortletEvents(status._ajaxInfo.getId(), false);
}
if (javaScriptPEvents != null) {
this.setSuffix(this.getSuffix() + javaScriptPEvents);
}
if (getPageContext().getRequest().getAttribute(REQUEST_ATTRIB_IS_AJAX_SUBFORM) != null &&
(Boolean)getPageContext().getRequest().getAttribute(REQUEST_ATTRIB_IS_AJAX_SUBFORM)) {
String formId = status.getRelevantForm();
if (formId != null) {
TMLForm form = getTMLContext().tmlformbyid(formId);
if (form != null) {
try {
String serializedInfo = FormBase.serializeFormInfo(form.getforminfo(), getTMLContext());
StringBuffer javaScript = new StringBuffer();
if (!status._isAjaxNoRefreshCall) {
javaScript.append("<script type=\"text/javascript\">");
}
javaScript.append("var form = document.forms['" + form.getformid() + "'];");
javaScript.append("if( form ) {");
javaScript.append("form.$forminfo.value = \"" + serializedInfo +"\";");
javaScript.append("form.removeAttribute('target');");
javaScript.append("form.removeAttribute('action');");
javaScript.append("}");
javaScript.append("else { alert('Oops, there is no form!'); };");
if (!status._isAjaxNoRefreshCall) {
javaScript.append("</script>");
}
this.setSuffix(getSuffix() + javaScript.toString());
} catch (UnsupportedEncodingException e) {
throw new TMLException("Unable to serialize form data.", e, false);
}
}
}
}
String redirectURL = (String) getPageContext().getRequest().getAttribute(WGACore.ATTRIB_REDIRECT);
if (redirectURL != null) {
StringBuffer javaScript = new StringBuffer();
if (!status._isAjaxNoRefreshCall) {
javaScript.append("<script type=\"text/javascript\">");
}
javaScript.append("location.href=\"" + WGUtils.encodeJS(redirectURL) + "\";");
if (!status._isAjaxNoRefreshCall) {
javaScript.append("</script>");
}
this.setSuffix(getSuffix() + javaScript.toString());
}
}
if (debugNode != null) {
debugNode.addAttribute("ended", (new Date()).toString());
debugNode.addAttribute("backenddocs", String.valueOf(getMainContext().db().getSessionContext().getTotalFetchedCores()));
Element rootElement = debugNode.getDocument().getRootElement();
rootElement.addAttribute("ended", DEBUG_TIMESTAMP_FORMAT.format(new Date()));
rootElement.addAttribute("tags", new Integer(getStatus().subtags).toString());
rootElement.addAttribute("backenddocs", String.valueOf(getMainContext().db().getSessionContext().getTotalFetchedCores()));
}
if (status.receptorTag != null) {
this.setResultOutput(false);
}
else {
this.pageContext.getRequest().setAttribute(WGACore.ATTRIB_TAGIDS, null);
}
recoverCurrentTMLAttributes((HttpServletRequest) pageContext.getRequest());
/* I think this is bogus now
// If parent tag, set it to current TMLContext, bc. tags in this TML module
// may have no complete pageContext objects any more after it was left
BaseTagStatus parentTag = getParentTag();
if (parentTag != null) {
getTMLContext().settag(parentTag);
}*/
}
/**
* Gets the resource
* @return Returns a String
*/
public String getResource() {
return resource;
}
/**
* Sets the resource
* @param resource The resource to set
*/
public void setResource(String resource) {
this.resource = resource;
}
/**
* Returns the db.
* @return String
*/
public String getRef() {
return ref;
}
/**
* Sets the db.
* @param db The db to set
*/
public void setRef(String db) {
this.ref = db;
}
/**
* @param request
*/
protected void storeCurrentTMLAttributes(HttpServletRequest request) {
Status status = (Status) getStatus();
Root.Status root;
if (status instanceof Root.Status) {
root = (Root.Status) status;
}
else {
root = status.getRootTag();
}
status._upperTml = (String) request.getAttribute(WGACore.ATTRIB_CURRENTTML);
request.setAttribute(WGACore.ATTRIB_CURRENTTML, root.resource);
}
protected void recoverCurrentTMLAttributes(HttpServletRequest request) {
Status status = (Status) getStatus();
request.setAttribute(WGACore.ATTRIB_CURRENTTML, status._upperTml);
}
/**
* restores the given ajaxInformation (options and context)
* @param ajaxInfo
*/
public void restoreEnvironmentFromAjaxCall(AjaxInfo ajaxInfo, HttpServletRequest request) {
Status status = (Status) getStatus();
// restore options
Map options = ajaxInfo.getOptions();
Iterator itOptions = options.values().iterator();
while (itOptions.hasNext()) {
TMLOption option = (TMLOption) itOptions.next();
if (!UNRECOVERABLE_OPTIONS.contains(option.getName())) {
status.setOption(option.getName(), option.getValue(), option.getScope());
}
}
// Restore design db option - must be here so following context change can use it
status.setOption(OPTION_DESIGNDB, status._ajaxInfo.getDesignDB(), null);
// restore context
// B00004832
TMLContext context = getTMLContext().context(ajaxInfo.getContextPath());
this.setTMLContext(context);
this.setChildTagContext(context);
// Restore profile store on end flag
if (getTMLContext().getprofile() != null) {
getTMLContext().getprofile().setSavedOnEnd(ajaxInfo.isSaveProfileOnEnd());
}
}
/**
* @return Returns the modulename.
*/
public String getModulename() {
return modulename;
}
/**
* @param modulename The modulename to set.
*/
public void setModulename(String modulename) {
this.modulename = modulename;
}
/**
* @return Returns the modulemediakey.
*/
public String getModulemediakey() {
return modulemediakey;
}
/**
* @param modulemediakey The modulemediakey to set.
*/
public void setModulemediakey(String modulemediakey) {
this.modulemediakey = modulemediakey;
}
/*
public void restoreTMLOptions(HttpServletRequest request) {
// restore options
String encryptedOptions = request.getParameter("$options");
if (encryptedOptions != null) {
try {
if (encryptedOptions.trim().equals("")) {
log.error("$OPTIONS parameter was posted with empty value. Cannon restore tml:options.");
return;
}
// decrypt
byte[] serOptions = this.getTMLContext().getCore().getDesEncrypter().decrypt(encryptedOptions);
// unzip
String unzipped = Zipper.unzip(serOptions);
// deserialize
HashMap options = (HashMap) new XStream().fromXML(unzipped);
// restore options
Iterator itKeys = options.keySet().iterator();
while (itKeys.hasNext()) {
String optionKey = (String) itKeys.next();
Object optionValue = options.get(optionKey);
this.setOption(optionKey, optionValue);
}
} catch (Exception e) {
String errMsg = "Error restoring tml:options from posted request.";
log.error(errMsg, e);
}
}
// restore context
String currentMediaKey = (String) this.getOption(OPTION_CURRENT_MEDIAKEY);
if (currentMediaKey != null) {
this.setContext()
}
}*/
private void filterOptions(Set optionsToFilter) {
Iterator options = getStatus().getTagOptions().values().iterator();
TMLOption option;
while (options.hasNext()) {
option = (TMLOption) options.next();
if (optionsToFilter.contains(option.getName()) && option.isLocalScope()) {
options.remove();
}
}
}
public TMLAction callAction(TMLActionLink actionLink, boolean ajax) throws TMLActionException, WGAPIException {
// Set params
ArrayList params = new ArrayList();
params.add(actionLink.getParam1());
params.add(actionLink.getParam2());
params.add(actionLink.getParam3());
params.add(actionLink.getParam4());
params.add(actionLink.getParam5());
// Look for correct sequence number to prevent action execution by page reload. Fail silently
HttpSession session = getTMLContext().gethttpsession();
if (!isCurrentSequenceNumber(actionLink, session, ajax)) {
return null;
}
// Look if action was rendered in this session - if not do not execute
if (!actionLink.getSessionID().equals(session.getId())) {
throw new TMLInvalidActionLinkException("The action was registered for a different session ID");
}
// Try to retrieve action context - defaults to context of this tag
TMLContext actionContext = getTMLContext();
if (!actionLink.getContextPath().equals(TMLActionLink.EMPTY_PARAM)) {
actionContext = actionContext.context(actionLink.getContextPath(), false);
// Could not retrieve context. Too dangerous to execute action under the wrong context.
if (actionContext == null) {
throw new TMLActionException("Unable to retrieve action context: " + actionLink.getContextPath());
}
} else {
//B00004602
// no context path - switch to dummy context of the given db
actionContext = getTMLContext().context("db:" + actionLink.getDbKey(), false);
// Could not retrieve dummy context. Too dangerous to execute action under the wrong context.
if (actionContext == null) {
throw new TMLActionException("Unable to retrieve action context: db:" + actionLink.getDbKey());
}
}
// Temporarily set portlet namespace, WebTML scope
BaseTagStatus tag = getTMLContext().getDesignContext().getTag();
TMLOptionPreserver preserver = new TMLOptionPreserver(tag);
preserver.preserve(Base.OPTION_PORTLET_NAMESPACE, actionLink.getPortletKey());
preserver.preserve(Base.OPTION_WEBTML_SCOPE, actionLink.getWebtmlScope());
try {
// Inner call, depends, if this a default action or not
if (actionLink.isDefaultAction()) {
actionContext.callDefaultAction(actionLink.getDefaultAction(), params);
if (actionLink.getPortletmode() != null && actionContext.getportlet() != null) {
actionContext.getportlet().setmode(actionLink.getPortletmode());
}
applyPortletContext(actionLink, actionContext);
return null;
}
else {
TMLAction tmlAction = (TMLAction) getTMLContext().getActionRegistration().get(actionLink.getActionKeyInteger());
if (tmlAction == null) {
throw new TMLActionException("Could not find action for key " + actionLink.getActionKey());
}
actionContext.callCustomAction(tmlAction, params);
if (actionLink.getPortletmode() != null && actionContext.getportlet() != null) {
if (getTMLContext().isdefined("actionresult")) {
ExpressionResult expressionResult = (ExpressionResult) getTMLContext().item("actionresult");
if (!expressionResult.isError() && (expressionResult.getResult() == null || expressionResult.getResult() instanceof String || !expressionResult.isFalse())) {
actionContext.getportlet().setmode(actionLink.getPortletmode());
}
}
}
applyPortletContext(actionLink, actionContext);
return tmlAction;
}
}
finally {
preserver.restore();
}
}
private void applyPortletContext(TMLActionLink actionLink, TMLContext actionContext) throws WGAPIException {
String pContextPath = actionLink.getPortletContextPath();
if (pContextPath != null && actionContext.getportlet() != null) {
if (pContextPath.trim().equalsIgnoreCase(TMLPortlet.PORTLETCONTEXT_NONE)) {
actionContext.getportlet().setcontext(null);
}
else {
actionContext.getportlet().getSessionContext().setContextPath(pContextPath);
}
}
}
private boolean isCurrentSequenceNumber(TMLActionLink actionLink, HttpSession session, boolean ajax) {
boolean correctSequence = true;
if (actionLink.isDefaultAction()) {
TMLAction.DefaultAction defaultAction = TMLAction.getDefaultAction(actionLink.getDefaultAction());
// When default action is unknown return true,
// so the action execution runs and issues warning "unknown default action"
if (defaultAction == null) {
return true;
}
if (!defaultAction.isDebounced()) {
return true;
}
if (!getCore().defaultActionSequenceIdAlreadyUsed(actionLink.getSequenceId())) {
getCore().defaultActionCalledWithSequenceId(actionLink.getSequenceId());
}
else {
correctSequence = false;
}
}
else {
TMLAction action = (TMLAction) getTMLContext().getActionRegistration().get(actionLink.getActionKeyInteger());
if (action == null) {
// Will fail later when action will be called. More speaking error message can be put out there.
return true;
}
// if debouncing is disabled we do not care about sequencenumber
if (!action.isDebounce() || (actionLink.getMode() != null && actionLink.getMode().equals(TMLActionLink.MODE_AJAX_NO_PORTLET_REFRESH))) {
return true;
}
if (!action.sequenceIdAlreadyUsed(actionLink.getSequenceId())) {
// action was not called with this sequenceId
action.calledWithSequenceId(actionLink.getSequenceId());
} else {
correctSequence = false;
}
}
return correctSequence;
}
}