/* * Copyright (C) 2000 - 2013 TagServlet Ltd * * This file is part of Open BlueDragon (OpenBD) CFML Server Engine. * * OpenBD is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * Free Software Foundation,version 3. * * OpenBD 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 OpenBD. If not, see http://www.gnu.org/licenses/ * * Additional permission under GNU GPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or combining * it with any of the JARS listed in the README.txt (or a modified version of * (that library), containing parts covered by the terms of that JAR, the * licensors of this Program grant you additional permission to convey the * resulting work. * README.txt @ http://www.openbluedragon.org/license/README.txt * * http://openbd.org/ * $Id: cfTRY.java 2330 2013-02-21 12:04:09Z alan $ */ package com.naryx.tagfusion.cfm.tag; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import com.naryx.tagfusion.cfm.engine.cfCatchClause; import com.naryx.tagfusion.cfm.engine.cfCatchData; import com.naryx.tagfusion.cfm.engine.cfData; import com.naryx.tagfusion.cfm.engine.cfSession; import com.naryx.tagfusion.cfm.engine.cfmAbortException; import com.naryx.tagfusion.cfm.engine.cfmBadFileException; import com.naryx.tagfusion.cfm.engine.cfmRunTimeException; import com.naryx.tagfusion.cfm.file.cfFile; import com.naryx.tagfusion.cfm.parser.runTime; import com.naryx.tagfusion.cfm.parser.script.ExceptionVarHandler; import com.naryx.tagfusion.cfm.parser.script.userDefinedFunction; public class cfTRY extends cfTag implements Serializable { static final long serialVersionUID = 1; public static String CFCATCHVAR = "cfcatch"; private transient List<cfCatchClause> cfcatchList; private transient cfTag finallyClause = null; public java.util.Map getInfo() { return createInfo("control", "Defines a block to which an error may occur and to be caught in a controlled manner"); } public String getEndMarker() { return "</CFTRY>"; } public void tagLoadingComplete() throws cfmBadFileException { buildCfcatchList(); } public cfTagReturnType render(cfSession _Session) throws cfmRunTimeException { // Note exceptionCatcher has to be created here as it takes note of file/tag stacks etc exceptionCatcher exHandler = new exceptionCatcher(this, cfcatchList); // Take a note of the active file before we run anything in this block cfFile activeFile = _Session.activeFile(); userDefinedFunction activeUDF = _Session.peekUserDefinedFunction(); try { cfTag innerTag; cfData token; int t = 0, s = 0, e = 0; for (int x = 0; x < controlList.length; x++) { if (controlList[x] == CHR_MARKER) { _Session.write(tagBody[s++]); } else if (_Session.isStopped()) { _Session.abortPageProcessing(); } else if (controlList[x] == TAG_MARKER) { innerTag = childTagList[t++]; if (innerTag instanceof cfCATCH || innerTag instanceof cfFINALLY) { break; } _Session.pushTag(innerTag); cfTagReturnType rt = innerTag.render(_Session); _Session.popTag(); if (!rt.isNormal()) { return rt; } } else if (controlList[x] == EXP_MARKER) { token = runTime.runExpression(_Session, expressionList[e++]); if (token != null) { _Session.write(token.getString()); } } } return cfTagReturnType.NORMAL; } catch (cfmAbortException ACF) { throw ACF; // catch and rethrow so it's not caught as RuntimeException below } catch (cfmRunTimeException RTE) { RTE.getCatchData().setSession(_Session); return handleException(_Session, exHandler, activeFile, activeUDF, RTE); } catch (RuntimeException e) { return handleException(_Session, exHandler, activeFile, activeUDF, new cfmRunTimeException(_Session, e)); } finally { if (finallyClause != null) { renderFinally(_Session); } } } /** * Renders the CFFINALLY block for this particular tag * * @param _Session * @throws cfmRunTimeException */ private void renderFinally(cfSession _Session) throws cfmRunTimeException { _Session.pushTag(finallyClause); finallyClause.render(_Session); _Session.popTag(); } private static cfTagReturnType handleException(cfSession _Session, exceptionCatcher _exHandler, cfFile _activeFile, userDefinedFunction activeUDF, cfmRunTimeException _rte) throws cfmRunTimeException { cfCatchClause clause = _exHandler.processRuntimeException(_Session, _activeFile, activeUDF, _rte); cfCATCH parent = clause.getParentTag(); // we may be within a cfcatch block so a cfcatch data already exists ExceptionVarHandler evh = new ExceptionVarHandler(_Session, CFCATCHVAR); try { evh.setExceptionVariable(_rte.getCatchData()); _Session.pushTag(parent); cfTagReturnType rt = parent.render(_Session); _Session.popTag(); evh.deleteExceptionVariable(); return rt; } catch (cfmRunTimeException rte) { evh.deleteExceptionVariable(); if (rte.isRethrow()) { // rethrowing same exception _exHandler.restoreSessionSnapshot(_Session); } throw rte; } } /** * create a list of CFCATCH tags, put TYPE="Any" last * @throws cfmBadFileException */ private void buildCfcatchList() throws cfmBadFileException { cfcatchList = new ArrayList<cfCatchClause>(); cfCATCH cfcatchAny = null; for (int i = 0; i < childTagList.length; i++) { cfTag childTag = childTagList[i]; if (childTag instanceof cfCATCH) { if (((cfCATCH) childTag).isCatchAny()) { if (cfcatchAny == null) { cfcatchAny = (cfCATCH) childTag; } else { cfcatchList = null; cfCatchData catchData = new cfCatchData(); catchData.setMessage("Cannot have multiple CFCATCH tags with attribute TYPE=\"Any\""); throw new cfmBadFileException(catchData); } } else { cfcatchList.add(new cfCatchClause((cfCATCH) childTag)); } } else if (childTag instanceof cfFINALLY) { if (finallyClause != null) { cfCatchData catchData = new cfCatchData(); catchData.setMessage("Cannot have multiple CFFINALLY tags within a CFTRY"); throw new cfmBadFileException(catchData); } else finallyClause = childTag; } } if (cfcatchAny != null) { cfcatchList.add(new cfCatchClause(cfcatchAny)); } if (cfcatchList.size() == 0 && finallyClause == null) { cfcatchList = null; cfCatchData catchData = new cfCatchData(); catchData.setMessage("There must be at least one CFCATCH OR a CFFINALLY within CFTRY"); throw new cfmBadFileException(catchData); } } }