/******************************************************************************* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. *******************************************************************************/ package org.apache.ofbiz.widget.model; import java.util.Map; import org.apache.ofbiz.base.util.Debug; import org.apache.ofbiz.base.util.UtilGenerics; import org.apache.ofbiz.base.util.UtilValidate; import org.apache.ofbiz.base.util.UtilXml; import org.apache.ofbiz.base.util.string.FlexibleStringExpander; import org.apache.ofbiz.entity.Delegator; import org.apache.ofbiz.entity.GenericEntity; import org.apache.ofbiz.entity.GenericEntityException; import org.apache.ofbiz.entity.transaction.TransactionUtil; import org.apache.ofbiz.service.LocalDispatcher; import org.apache.ofbiz.widget.renderer.ScreenRenderException; import org.apache.ofbiz.widget.renderer.ScreenStringRenderer; import org.w3c.dom.Element; /** * Widget Library - Screen model class */ @SuppressWarnings("serial") public class ModelScreen extends ModelWidget { public static final String module = ModelScreen.class.getName(); private final String sourceLocation; private final FlexibleStringExpander transactionTimeoutExdr; private final Map<String, ModelScreen> modelScreenMap; private final boolean useTransaction; private final boolean useCache; private final ModelScreenWidget.Section section; /** XML Constructor */ public ModelScreen(Element screenElement, Map<String, ModelScreen> modelScreenMap, String sourceLocation) { super(screenElement); this.sourceLocation = sourceLocation; this.transactionTimeoutExdr = FlexibleStringExpander.getInstance(screenElement.getAttribute("transaction-timeout")); this.modelScreenMap = modelScreenMap; this.useTransaction = "true".equals(screenElement.getAttribute("use-transaction")); this.useCache = "true".equals(screenElement.getAttribute("use-cache")); // read in the section, which will read all sub-widgets too Element sectionElement = UtilXml.firstChildElement(screenElement, "section"); if (sectionElement == null) { throw new IllegalArgumentException("No section found for the screen definition with name: " + getName()); } this.section = new ModelScreenWidget.Section(this, sectionElement, true); } @Override public void accept(ModelWidgetVisitor visitor) throws Exception { visitor.visit(this); } public String getTransactionTimeout() { return transactionTimeoutExdr.getOriginal(); } public Map<String, ModelScreen> getModelScreenMap() { return modelScreenMap; } public boolean getUseTransaction() { return useTransaction; } public boolean getUseCache() { return useCache; } public ModelScreenWidget.Section getSection() { return section; } public String getSourceLocation() { return sourceLocation; } /** * Renders this screen to a String, i.e. in a text format, as defined with the * ScreenStringRenderer implementation. * * @param writer The Writer that the screen text will be written to * @param context Map containing the screen context; the following are * reserved words in this context: * - parameters (contains any special initial parameters coming in) * - userLogin (if a user is logged in) * - autoUserLogin (if a user is automatically logged in, ie no password has been entered) * - formStringRenderer * - request, response, session, application (special case, only in HTML contexts, etc) * - delegator, dispatcher, security * - null (represents a null field value for entity operations) * - sections (used for decorators to reference the sections to be decorated and render them) * @param screenStringRenderer An implementation of the ScreenStringRenderer * interface that is responsible for the actual text generation for * different screen elements; implementing your own makes it possible to * use the same screen definitions for many types of screen UIs */ public void renderScreenString(Appendable writer, Map<String, Object> context, ScreenStringRenderer screenStringRenderer) throws ScreenRenderException { // make sure the "nullField" object is in there for entity ops context.put("nullField", GenericEntity.NULL_FIELD); // wrap the whole screen rendering in a transaction, should improve performance in querying and such Map<String, String> parameters = UtilGenerics.cast(context.get("parameters")); boolean beganTransaction = false; int transactionTimeout = -1; if (parameters != null) { String transactionTimeoutPar = parameters.get("TRANSACTION_TIMEOUT"); if (transactionTimeoutPar != null) { try { transactionTimeout = Integer.parseInt(transactionTimeoutPar); } catch (NumberFormatException nfe) { String msg = "TRANSACTION_TIMEOUT parameter for screen [" + this.sourceLocation + "#" + getName() + "] is invalid and it will be ignored: " + nfe.toString(); Debug.logWarning(msg, module); } } } if (transactionTimeout < 0 && !transactionTimeoutExdr.isEmpty()) { // no TRANSACTION_TIMEOUT parameter, check screen attribute String transactionTimeoutStr = transactionTimeoutExdr.expandString(context); if (UtilValidate.isNotEmpty(transactionTimeoutStr)) { try { transactionTimeout = Integer.parseInt(transactionTimeoutStr); } catch (NumberFormatException e) { Debug.logWarning(e, "Could not parse transaction-timeout value, original=[" + transactionTimeoutExdr + "], expanded=[" + transactionTimeoutStr + "]", module); } } } try { // If transaction timeout is not present (i.e. is equal to -1), the default transaction timeout is used // If transaction timeout is present, use it to start the transaction // If transaction timeout is set to zero, no transaction is started if (useTransaction) { if (transactionTimeout < 0) { beganTransaction = TransactionUtil.begin(); } if (transactionTimeout > 0) { beganTransaction = TransactionUtil.begin(transactionTimeout); } } // render the screen, starting with the top-level section this.section.renderWidgetString(writer, context, screenStringRenderer); TransactionUtil.commit(beganTransaction); } catch (Exception e) { String errMsg = "Error rendering screen [" + this.sourceLocation + "#" + getName() + "]: " + e.toString(); Debug.logError(errMsg + ". Rolling back transaction.", module); try { // only rollback the transaction if we started one... TransactionUtil.rollback(beganTransaction, errMsg, e); } catch (GenericEntityException e2) { Debug.logError(e2, "Could not rollback transaction: " + e2.toString(), module); } // throw nested exception, don't need to log details here: Debug.logError(e, errMsg, module); // after rolling back, rethrow the exception throw new ScreenRenderException(errMsg, e); } } public LocalDispatcher getDispatcher(Map<String, Object> context) { LocalDispatcher dispatcher = (LocalDispatcher) context.get("dispatcher"); return dispatcher; } public Delegator getDelegator(Map<String, Object> context) { Delegator delegator = (Delegator) context.get("delegator"); return delegator; } }