org.joty.server.JotyServer Maven / Gradle / Ivy
Show all versions of joty-server Show documentation
/*
Copyright (c) 2013-2015, Stefano Pizzocaro. All rights reserved. Use is subject to license terms.
This file is part of Joty 2.0 Core.
Joty 2.0 Core is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Joty 2.0 Core 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Joty 2.0 Core. If not, see .
*/
package org.joty.server;
import java.io.*;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Vector;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.sql.DataSource;
import javax.xml.bind.DatatypeConverter;
import org.joty.access.Accessor;
import org.joty.access.BirtManager;
import org.joty.access.DbManager;
import org.joty.access.Instantiator;
import org.joty.access.Logger;
import org.joty.access.MethodExecutor;
import org.joty.access.PostStatement;
import org.joty.access.DbManager.DbConnectionGrabber;
import org.joty.common.*;
import org.joty.common.ConfigFile.ConfigException;
import org.joty.common.BasicPostStatement.Item;
import org.joty.common.ReportManager.Parameter;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
/**
* It is the Joty Server implementation.
*
* It accepts Http requests from the org.joty.web.WebClient object running on
* the client side. On the first call from a client or on new Http session (due
* to expiration of the preceding one), it forces the user to authenticate and
* manages his authentication on the dbms.
*
* the server looks in the requesting Url for the query string parameter
* 'command' that can worth as follow: when the request is
* forwarded as http GET admitted values are {config, end}, when the request is
* a http POST possible values are {query, exec, trans, report}.
*
* In the case of 'config' value for the Joty command another query string
* parameter comes in to play: 'type' = {conf, confX, jotyLang, appLang}. Even
* for other Joty commands other query string parameters play a role: this can
* be encountered along the {@code doPost} implementation.
*
* As the WebClient the server uses UTF8 encoding a part from binary content for
* which a single byte encoding is used.
*
*/
public class JotyServer extends HttpServlet implements JotyMessenger {
/**
* An inner class for getting the opportunity to have intrinsic log activity
* for the returned stream without worry about it. It is a simple wrapper
* for the {@code PrintWriter} used that adds a StringBuilder as further
* delegate, that will grow in its content as the PrintWriter object receives content.
*/
class OutPrinterWrapper {
PrintWriter m_writer;
OutPrinterWrapper() {
m_writer = null;
};
OutPrinterWrapper(PrintWriter val) {
m_writer = val;
};
void append(String text) {
m_writer.append(text);
if (m_debug)
m_responseText.append(text);
}
}
final String MY_USERUSERNAME = "me.userName";
final String MY_PWD = "me.password";
final String MY_SHK = "me.sharingKey";
private static final long serialVersionUID = 1L;
final String m_genIDtheme = "GenID";
private PrintWriter m_outWriter;
protected Connection m_conn;
private String m_user;
private String m_password;
protected String m_command;
protected Vector m_postStatements;
protected PostStatement m_queryDefPostStatement;
protected Vector m_bytesElems;
protected boolean m_success;
protected ErrorCarrier m_errorCarrier;
/**
* holds the generated values resulting by the execution of {@link #dbExecute()}
*/
protected Vector m_returnedValues;
private String m_sessionID;
private byte[] m_bytes;
protected ConfigFile m_configuration;
protected ConfigFile m_serverConfig;
private long m_autoIdVal;
private String m_autoId;
private DbManager m_dbManager;
private String m_dbmsSessionPreset;
private int m_intDigitDim;
private boolean m_configurationLoaded;
private boolean m_fieldOrdinality;
protected String m_singleByteEncoding = Utilities.m_singleByteEncoding;
protected boolean m_logDbActions;
protected XmlTextEncoder m_xmlEncoder;
protected boolean m_debug;
protected String m_dbLogName;
protected boolean m_use_BIRT;
protected BirtManager m_BirtManager;
private ReportManager m_reportManager;
CaselessStringKeyMap m_smallBlobs;
private int m_statementIndex;
StringBuilder m_responseText;
protected Accessor m_accessor;
protected boolean m_remoteAccessor;
protected ParamContext m_queryDefParamContext;
private String m_paginationPageSize;
private String m_paginationQuery;
protected DbConnectionGrabber m_connGrabber;
protected MethodExecutor m_methodExecutor;
private CaselessStringKeyMap m_JotyLangs;
private CaselessStringKeyMap m_JotyAppLangs;
private String m_languages;
private Vector m_langVector;
private boolean m_shared;
private String m_sharingKeyField;
private String m_sharingKey;
private LangLiteralRetCodeMapper m_langLiteralRetCodeMapper;
protected boolean m_msSqlServer;
private boolean m_hostLogNameSet;
public JotyServer() {
super();
m_postStatements = new Vector();
m_bytesElems = new Vector();
m_returnedValues = new Vector();
m_smallBlobs = new CaselessStringKeyMap(this);
m_sessionID = "";
m_queryDefPostStatement = new PostStatement(this);
Utilities.setMessanger(this);
}
/**
* This method manages the creation of a record when no Insert sql statement
* has been rendered by the client but only the table and the
* auto-incrementing id field are indicated and, furthermore, the jdbc
* driver is expected to support the creation of records by means of
* {@code moveToInsertRow} and {@code insertRow} invocations of the
* ResultSet object, built on the specified database table.
*
* @param postedStmnt
* the BasicPostStatement object containing needed information
* @return the auto generated id long value.
* @throws SQLException
* @throws NamingException
*
* @see #dbExecute()
*/
private long addNewAndGetID(BasicPostStatement postedStmnt) throws SQLException, NamingException {
Statement statement;
long retVal = 0;
m_connGrabber.acquireConnection();
statement = m_conn.createStatement();
String sql = String.format("Select %1$s.* from %1$s", postedStmnt.m_genTable);
ResultSet result = statement.executeQuery(sql);
ResultSetMetaData metadata = result.getMetaData();
int colCount = metadata.getColumnCount();
int index;
String fieldName;
int nSqlType;
long lPrecision; // size
int nScale; // decimals
CaselessStringKeyMap setFields = new CaselessStringKeyMap(this);
for (Item item : postedStmnt.m_items)
setFields.put(item.name, item.valueLiteral);
result.moveToInsertRow();
String valueStr = null;
for (int i = 0; i < colCount; i++) {
index = i + 1;
fieldName = metadata.getColumnLabel(index);
valueStr = setFields.get(fieldName);
if (valueStr != null) {
if (valueStr.compareToIgnoreCase("null") == 0)
result.updateNull(fieldName);
else {
nSqlType = metadata.getColumnType(index);
lPrecision = metadata.getPrecision(index);
nScale = metadata.getScale(index);
switch (nSqlType) {
case Types.CHAR:
case Types.VARCHAR:
result.updateString(fieldName, valueStr);
break;
case Types.FLOAT:
result.updateFloat(fieldName, Float.parseFloat(valueStr));
break;
case Types.DOUBLE:
result.updateDouble(fieldName, Double.parseDouble(valueStr));
break;
case Types.REAL:
case Types.NUMERIC:
case Types.BIGINT:
if (nScale == 0 || nScale == -127)
if (lPrecision > m_intDigitDim)
result.updateLong(fieldName, Long.parseLong(valueStr));
else
result.updateInt(fieldName, Integer.parseInt(valueStr));
else
result.updateDouble(fieldName, Double.parseDouble(valueStr));
break;
case Types.INTEGER:
result.updateLong(fieldName, Long.parseLong(valueStr));
break;
case Types.SMALLINT:
result.updateInt(fieldName, Integer.parseInt(valueStr));
break;
case 11:
case Types.DATE:
result.updateDate(fieldName, Date.valueOf(valueStr));
break;
case Types.TIMESTAMP:
result.updateDate(fieldName, Date.valueOf(valueStr));
}
}
}
}
result.insertRow();
result.last();
retVal = result.getInt(m_autoId);
statement.close();
m_connGrabber.releaseConnection();
return retVal;
}
protected boolean attributePredicate(HttpServletRequest request, String attr, boolean defTruth) {
String valueStr = request.getParameter(attr);
return valueStr == null ? defTruth : valueStr.equals("y");
}
protected void beginTrans() throws SQLException, NamingException {
m_connGrabber.acquireConnection();
}
/**
* Envelopes the content of the {@code m_returnedValues} member in a convenient xml structure.
*
* @return the rendered xml text.
*
* @see #dbExecute()
* @see #m_returnedValues
*/
protected String buildXmlResult() {
StringBuilder retVal = new StringBuilder();
retVal.append("");
retVal.append(m_success ? "Ok" : "Nok");
retVal.append(" ");
retVal.append(m_xmlEncoder.encode(m_errorCarrier.m_exceptionMsg.toString(), false));
retVal.append(" ");
String openTag, closeTag;
if (m_success) {
retVal.append(String.format("<%1$s>", m_genIDtheme + "s"));
for (int i = 0; i < m_returnedValues.size(); i++) {
openTag = String.format("<%1$s>", m_genIDtheme);
closeTag = String.format("%1$s>", m_genIDtheme);
retVal.append(openTag);
retVal.append(String.valueOf(m_returnedValues.get(i)));
retVal.append(closeTag);
}
retVal.append(String.format("%1$s>", m_genIDtheme + "s"));
} else
retVal.append("" + m_errorCarrier.code + "
");
retVal.append(" ");
if (!m_success)
logUncodedFailureReport(m_errorCarrier.m_exceptionMsg.toString());
return retVal.toString();
}
private boolean checkConfigFileLoading(CaselessStringKeyMap cfMap) {
for (Iterator it = cfMap.entrySet().iterator(); it.hasNext();)
if (((Entry) it.next()).getValue().m_document == null) {
m_configurationLoaded = false;
break;
}
return m_configurationLoaded;
}
protected boolean checkCredentials(HttpServletRequest request, String command, boolean sessionIsALive) throws IOException {
HttpSession session = request.getSession(true);
m_user = null;
m_password = null;
if (sessionIsALive) {
m_user = (String) session.getAttribute(MY_USERUSERNAME);
m_password = (String) session.getAttribute(MY_PWD);
if (m_shared)
m_sharingKey = (String) session.getAttribute(MY_SHK);
}
if (command != null && command.equals("login")) {
m_user = request.getParameter("user");
m_password = request.getParameter("pwd");
session.setAttribute(MY_USERUSERNAME, m_user);
session.setAttribute(MY_PWD, m_password);
if (m_shared) {
m_sharingKey = request.getParameter("shK");
session.setAttribute(MY_SHK, m_sharingKey);
}
}
return m_user != null && !m_user.isEmpty();
}
private boolean checkDbManager() {
boolean retVal = m_dbManager != null;
if (!retVal) {
m_errorCarrier.m_exceptionMsg.append("DbManager object not instantiated - check the log about the server start up");
m_success = false;
}
return retVal;
}
protected boolean checkRequestPostContent(String postedContent) {
boolean retVal = Utilities.xsdValidate(Utilities.getXmlDocument(postedContent),
getServletContext().getRealPath("/JotyRequest.xsd"),
"request");
if (!retVal)
m_errorCarrier.m_exceptionMsg.append("Invalid request format");
return retVal;
}
/**
* Checks if session is alive.
*
* If session is not identified by cookies the session id is saved to be
* returned, later (see {@code renderXmlFooter}), to the client for future
* session-identifying requests.
*
* @param request
* the request object
* @return true if session is still alive
* @throws IOException
*/
private boolean checkSession(HttpServletRequest request) throws IOException {
HttpSession session = request.getSession(true);
boolean expiredOrNew = session.isNew();
if (!request.isRequestedSessionIdFromCookie())
m_sessionID = session.getId();
return !expiredOrNew;
}
protected boolean commit() {
boolean retVal = false;
Exception exception = null;
try {
m_conn.commit();
retVal = true;
} catch (SecurityException e) {
exception = e;
} catch (IllegalStateException e) {
exception = e;
} catch (SQLException e) {
m_errorCarrier.setSqlErrorCode(e);
exception = e;
}
if (!retVal) {
if (exception != null) {
jotyMessage(exception);
m_errorCarrier.m_exceptionMsg.append(exception.getMessage());
}
rollback();
}
return retVal;
}
/**
* Performs the execution of the statements held by the
* {@code m_postStatements} member either the transaction is the case or a
* single statement is to be executed. For each PostStatement object found
* in the vector, it calls
* {@link org.joty.access.Accessor#setPostStatement(PostStatement, boolean)} by means of
* which the ParamContext instance used by the Accessor object is fed with
* new ContextParam objects extracted by the set of Item objects.
*
* If the {@code m_method} member has a value the
* {@code MethodExecutor#exec(BasicPostStatement, Boolean, Connection)} is
* invoked.
*
* If the {@code m_sql} member has a value {@code executeSql} is called
* after the sql text could have been transformed either by a literal
* substitution or by the substitutions of every numbered 'gen-id' place
* holders with their respective Id instances previously generated upon
* the execution of preceding BasicPostStatement objects in the same call of this
* method ;
*
* In all other case suitable actions take place; these cases manage old
* features of the previous version of Joty that have been made surviving.
*
* @throws SQLException
* @throws NamingException
*
* @see MethodExecutor
* @see #executeSql(String)
* @see PostStatement#nameSubst(Accessor, String)
* @see #idSqlSubst(String)
*/
protected void dbExecute() throws SQLException, NamingException {
if (m_command.equals("trans"))
beginTrans();
String getTable;
String sqlStmnt;
String verifyExpr;
PostStatement postedStmnt = null;
HashSet nonManagedRollbackIndexes = new HashSet();
m_statementIndex = 0;
if (m_accessor != null)
m_accessor.clearParamContext();
for (int i = 0; i < m_postStatements.size(); i++) {
postedStmnt = (PostStatement) m_postStatements.get(i);
if (postedStmnt.m_nonManagedRollbackActionIden >= 0) {
if (m_accessor != null)
m_accessor.setPostStatement(postedStmnt, true);
getTable = postedStmnt.m_genTable;
verifyExpr = postedStmnt.m_verifyExpr;
sqlStmnt = postedStmnt.m_sql;
m_autoId = postedStmnt.m_autoId;
if (postedStmnt.m_method.length() > 0 && postedStmnt.m_AccessorContext.length() == 0)
m_success = m_methodExecutor.exec(postedStmnt, m_command.equals("exec"), m_conn);
else if (postedStmnt.m_autoId.length() > 0) {
long id;
if (sqlStmnt.length() > 0) {
m_autoIdVal = 0;
m_success = executeSql(idSqlSubst(postedStmnt.nameSubst(m_accessor, sqlStmnt)));
id = m_autoIdVal;
} else
id = addNewAndGetID(postedStmnt);
m_success &= id != 0;
if (!m_success)
m_errorCarrier.m_exceptionMsg.append(" - Failure on getting auto-increment ID !");
m_returnedValues.add(String.valueOf(id));
} else if (checkDbManager()) {
if (getTable.length() > 0) {
m_dbManager.setConn(m_conn);
m_success = true;
if (m_success) {
long idGot = m_dbManager.getId(sqlStmnt);
if (idGot == 0) {
m_success = false;
m_errorCarrier.m_exceptionMsg.append(" - Failure on getting table generated ID !");
} else
m_returnedValues.add(String.valueOf(idGot));
}
} else {
if (verifyExpr.length() > 0) {
m_dbManager.setConn(m_conn);
m_success = true;
if (m_success)
m_success = m_dbManager.validate(verifyExpr);
}
if (m_success && sqlStmnt.length() > 0)
m_success = executeSql(idSqlSubst(postedStmnt.nameSubst(m_accessor, sqlStmnt)));
}
}
}
if (m_success) {
if (postedStmnt.m_nonManagedRollbackActionIden > 0)
nonManagedRollbackIndexes.add(postedStmnt.m_nonManagedRollbackActionIden);
} else
break;
}
if ( ! m_success) {
for (int i = 0; i < m_postStatements.size(); i++) {
postedStmnt = (PostStatement) m_postStatements.get(i);
if (postedStmnt.m_nonManagedRollbackActionIden < 0 && nonManagedRollbackIndexes.contains(-postedStmnt.m_nonManagedRollbackActionIden)) {
if (m_accessor != null)
m_accessor.setPostStatement(postedStmnt, true);
sqlStmnt = postedStmnt.m_sql;
if (sqlStmnt.length() > 0)
executeSql(postedStmnt.nameSubst(m_accessor, sqlStmnt));
}
}
m_success = false;
}
if (m_command.equals("trans"))
endTrans();
}
/**
* It is responsible of building the Joty response for the request of configuration
* data and for the request of ending the session.
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
String command = request.getParameter("command");
OutPrinterWrapper outPrinterWrapper = new OutPrinterWrapper(m_outWriter);
if (command == null)
outPrinterWrapper.append("Hi,
this is Joty Server (v. 2.0.3) !
www.joty.org");
else {
boolean sessionWasAlive = checkSession(request);
renderXmlHeader(outPrinterWrapper);
if (command.equals("end")) {
if (sessionWasAlive) {
HttpSession session = request.getSession(true);
String userName = (String) session.getAttribute(MY_USERUSERNAME);
session.removeAttribute(MY_USERUSERNAME);
session.removeAttribute(MY_PWD);
session.invalidate();
jotyWarning(" User " + userName + " exited (session id = " + m_sessionID + ")");
}
outPrinterWrapper.append("Ok ");
} else if (command.equals("config")) {
if (m_configurationLoaded)
try {
String type = request.getParameter("type");
String lang = request.getParameter("lang");
if (type.compareToIgnoreCase("confX") == 0 && m_remoteAccessor)
renderError(outPrinterWrapper, "Forbidden request !");
else
outPrinterWrapper.append(
String.format("Ok %1$s ",
m_xmlEncoder.encode(
(type.compareToIgnoreCase("conf") == 0 ?
m_configuration :
type.compareToIgnoreCase("appLang") == 0 ?
m_JotyAppLangs.get(lang) :
m_JotyLangs.get(lang)
).m_fileContent,
false)));
} catch (Exception e) {
jotyMessage(e);
m_configurationLoaded = false;
}
if (!m_configurationLoaded)
renderError(outPrinterWrapper, "At least one configuration source is missing on the server !");
} else if (sessionWasAlive)
renderError(outPrinterWrapper, "Illegal Joty server invocation : GET/" + command);
else
renderSessExpXml(outPrinterWrapper);
renderXmlFooter(outPrinterWrapper);
}
endWriter(outPrinterWrapper);
} catch (Exception e) {
jotyMessage(e);
}
}
/**
* Builds the most part of the responses since almost all the Joty web
* commands are dispatched through an http post command, because they
* require a body to be delivered. It invokes {@code getPostedBodyElements}
* for loading into convenient structures the data present in the request
* body.
*
* then, again depending on the particular Joty web command, the task is
* dispatched to other serving methods to be accomplished.
*
* If the application works in 'Accessor mode' and the application
* {@code Accessor} object lives on the server side this object is used
* either for picking the effective statements up in order to be executed or to apply
* literals substitution on the statements coming from the request.
*
* @see #getPostedBodyElements
* @see #getXmlFromDb
* @see #getResponseFromLogin
* @see #getReportXml
* @see #dbExecute
* @see Accessor
*
*
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
String postedContent = getPostedContent(request);
if (m_debug)
jotyWarning(" Posted content : \n " + postedContent);
m_errorCarrier.clear();
boolean tryReturnInvalidReqFormat = false;
if (m_debug)
tryReturnInvalidReqFormat = !checkRequestPostContent(postedContent);
String command = request.getParameter("command");
OutPrinterWrapper outPrinterWrapper = new OutPrinterWrapper(m_outWriter);
boolean credentialsAvailable = checkCredentials(request, command, checkSession(request));
if (command == null) {
outPrinterWrapper.append("
Hi,
this is Joty Server !
You posted: " +
postedContent + "");
} else {
m_command = command;
if (outPrinterWrapper.m_writer != null)
renderXmlHeader(outPrinterWrapper);
if (credentialsAvailable) {
m_success = !tryReturnInvalidReqFormat;
if (m_success)
try {
String mainSqlStmnt = getPostedBodyElements(postedContent);
boolean login = m_command.equals("login");
if (m_command.equals("query") || login) {
m_connGrabber.acquireConnection();
String sql = null;
if (mainSqlStmnt == null) {
m_success = false;
if (m_accessor == null && !login)
m_errorCarrier.m_exceptionMsg.append("Accessor missing !");
else {
if (login) {
sql = "select 1 as joty" + (m_msSqlServer ? "" : " from dual");
m_success = true;
} else {
m_accessor.setPostStatement(m_queryDefPostStatement);
if (m_shared)
m_accessor.setSharingKey(m_sharingKey);
sql = m_accessor.getQueryFromPostStatement();
if (!m_shared || !m_accessor.sharingViolation()) {
if (m_accessor.dataDefFound() || m_accessor.substitutingLiteral())
m_success = true;
else
m_errorCarrier.m_exceptionMsg.append(m_accessor.m_ddNotFoundMsg);
}
}
}
} else
sql = mainSqlStmnt;
if (m_success) {
String xml = m_command.equals("query") ?
getXmlFromDb(sql, !attributePredicate(request, "data", true), attributePredicate(request, "bin", false)) :
getResponseFromLogin(m_user, m_password, sql);
m_connGrabber.releaseConnection();
outPrinterWrapper.append(xml);
}
} else if (m_command.equals("report")) {
outPrinterWrapper.append(m_BirtManager == null ?
getResultFromFailure("NO_BIRT") :
getReportXml(request.getParameter("name"),
request.getParameter("type"),
request.getParameter("lang"),
attributePredicate(request, "twoProc", true)));
} else {
dbExecute();
if (m_success)
outPrinterWrapper.append(buildXmlResult());
}
} catch (SQLException e) {
jotyMessage(e);
m_errorCarrier.setSqlException(e);
m_success = false;
} catch (NamingException e) {
jotyMessage(e);
m_errorCarrier.m_exceptionMsg.append(e.getMessage());
m_success = false;
} catch (Exception e) {
jotyMessage(e);
m_errorCarrier.m_exceptionMsg.append(" Joty Server low level error !");
m_success = false;
}
if (!m_success) {
outPrinterWrapper.append(buildXmlResult());
}
} else
renderSessExpXml(outPrinterWrapper);
renderXmlFooter(outPrinterWrapper);
}
endWriter(outPrinterWrapper);
} catch (Exception e) {
jotyMessage(e);
}
}
protected String encodedBytes() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
if (m_bytes != null && m_bytes.length > 0) {
baos.write(m_bytes);
return m_xmlEncoder.encode(baos.toString(m_singleByteEncoding), true);
}
} catch (IOException e) {
jotyMessage(e);
return null;
}
return null;
}
protected void endTrans() {
if (m_success)
m_success = commit();
else
rollback();
m_connGrabber.releaseConnection();
}
private void endWriter(OutPrinterWrapper wrapper) {
wrapper.m_writer.flush();
wrapper.m_writer.close();
if (m_debug)
jotyWarning(" Response content : \n " + m_responseText.toString());
}
/**
* Executes an sql statement either it be participating in a transaction or standing alone
* @param sql the statement text
* @return true if success
*
* @see #executeStmnt
*/
protected boolean executeSql(String sql) {
m_success = true;
Boolean atomic = m_command.equals("exec");
Exception exc = null;
try {
if (atomic)
m_connGrabber.acquireConnection(true);
if (m_success)
m_success = executeStmnt(sql);
if (atomic)
m_connGrabber.releaseConnection();
} catch (SQLException e) {
jotyMessage(e);
exc = e;
} catch (NamingException e) {
jotyMessage(e);
exc = e;
} finally {
if (atomic)
m_connGrabber.releaseConnection();
}
if (exc != null) {
m_success = false;
Logger.appendToHostLog(" " + exc.getMessage(), true);
Logger.appendToLog(m_dbLogName, exc.getMessage());
m_errorCarrier.m_exceptionMsg.append(exc.getMessage());
}
return m_success;
}
/**
* Serves {@code executeSql} in executing an sql statement.
*
* As it can be noted currently the method manages only binary writing if
* the {@code m_bytesElems} vector is not empty. This is not a limitation
* because in Joty 2.0 still a writing of a large blob object is managed in
* a dedicated way and now, at most, is accompanied by the writing of a
* small blob object. That is, it is never embedded in a transaction set of
* statements composed by sql of various nature.
*
* In the other case the method manages statement execution that either
* infers value generation for the field indicated by the {@code m_autoId}
* member or not.
*
*
* @param sql
* the statement text
* @return true if success
* @throws NamingException
* @see org.joty.workstation.gui.ImageComponent
*
*/
protected Boolean executeStmnt(String sql) throws NamingException {
boolean success = true;
try {
if (m_logDbActions)
Logger.appendToLog(m_dbLogName, sql, false, m_user, false);
if (m_bytesElems.size() > 0) {
PreparedStatement stmnt = m_conn.prepareStatement(sql);
stmnt.setBytes(1, m_bytesElems.get(m_statementIndex));
stmnt.executeUpdate();
stmnt.close();
m_statementIndex++;
} else {
PreparedStatement stmnt = null;
if (m_autoId.length() > 0) {
stmnt = m_conn.prepareStatement(sql, new String[] { m_autoId });
stmnt.executeUpdate();
ResultSet rset = stmnt.getGeneratedKeys();
m_autoIdVal = 0;
if (rset.next())
m_autoIdVal = rset.getLong(1);
} else {
stmnt = m_conn.prepareStatement(sql);
stmnt.executeUpdate();
}
stmnt.close();
}
} catch (SQLException e) {
jotyWarning("Sql : \n " + sql);
jotyMessage(e);
m_errorCarrier.setSqlException(e);
success = false;
}
return success;
}
private boolean getConfBool(String literal) throws ConfigException {
String strVal = getConfStr(literal);
return strVal == null ? false : Boolean.parseBoolean(getConfStr(literal));
}
private int getConfInt(String literal) throws ConfigException {
String strVal = getConfStr(literal);
return strVal == null ? 0 : Integer.parseInt(getConfStr(literal));
}
private String getConfStr(String literal) throws ConfigException {
return m_configuration.configTermValue(literal);
}
protected String getNodeValue(Node node, String name) {
String retVal = "";
if (node.getNodeName().compareToIgnoreCase(name) == 0)
retVal = node.getTextContent();
return retVal;
}
/**
* It extracts the request content and depending on the type of the command,
* read from the query string parameters, loads it in suitable data
* structures.
*
* @param postedContent the body of the Http Post command
* @return the first sql statement encountered during the parsing
* @throws IOException
*
* @see #m_queryDefPostStatement
* @see #m_postStatements
* @see #m_reportManager
* @see ReportManager#m_params
* @see #m_smallBlobs
*
*/
private String getPostedBodyElements(String postedContent) throws IOException {
m_postStatements.removeAllElements();
m_bytesElems.removeAllElements();
m_returnedValues.removeAllElements();
Document doc = Utilities.getXmlDocument(postedContent);
Node root = doc.getDocumentElement();
Node firstLevelNode = root.getFirstChild();
Node currNode = firstLevelNode;
String firstStmnt = null;
if (m_command.equals("trans") || m_command.equals("exec")) {
currNode = currNode.getFirstChild();
firstStmnt = "";
if (currNode.getNodeName().equals("Stmnt")) {
Node currStmnt;
currStmnt = currNode;
while (currStmnt != null) {
currNode = currStmnt.getFirstChild();
PostStatement postStatement = new PostStatement(this);
readPostStatement(postStatement, currNode);
if (firstStmnt.length() == 0)
firstStmnt = postStatement.m_sql;
m_postStatements.add(postStatement);
currStmnt = currStmnt.getNextSibling();
}
}
firstLevelNode = firstLevelNode.getNextSibling();
while (firstLevelNode != null) {
if (firstLevelNode.getNodeName().equals("Binary"))
m_bytesElems.add(m_xmlEncoder.decode(firstLevelNode.getTextContent(), true).getBytes(m_singleByteEncoding));
firstLevelNode = firstLevelNode.getNextSibling();
}
} else if (m_command.equals("report")) {
if (m_BirtManager != null) {
m_reportManager.resetParams();
currNode = currNode.getFirstChild();
Node currParam;
currParam = currNode;
int paramType;
String literalValue = null;
while (currParam != null) {
currNode = currParam.getFirstChild();
Parameter param = m_reportManager.new Parameter();
param.name = getNodeValue(currNode, "Name");
currNode = currNode.getNextSibling();
literalValue = getNodeValue(currNode, "Val");
currNode = currNode.getNextSibling();
paramType = Integer.parseInt(getNodeValue(currNode, "Type"));
param.type = paramType;
param.setValue(literalValue, paramType);
m_reportManager.m_params.add(param);
currParam = currParam.getNextSibling();
}
}
} else if (currNode.getNodeName().equals("QueryStmnt") || currNode.getNodeName().equals("QueryDef")) {
Node queryNode = currNode;
if (currNode.getNodeName().equals("QueryStmnt"))
firstStmnt = currNode.getTextContent();
else {
currNode = currNode.getFirstChild();
m_queryDefPostStatement.clear();
readPostStatement((PostStatement) m_queryDefPostStatement, currNode);
}
currNode = queryNode.getNextSibling();
m_smallBlobs.clear();
if (currNode != null && currNode.getNodeName().equals("SmallBlobs")) {
currNode = currNode.getFirstChild();
int i = 0;
while (currNode != null) {
m_smallBlobs.put(currNode.getTextContent(), i);
currNode = currNode.getNextSibling();
i++;
}
}
}
return firstStmnt;
}
/**
* Gets the body of the Http Post command.
* @param request
* @return the content of the body
*/
protected String getPostedContent(HttpServletRequest request) {
try {
return Utilities.stringFromInputStream(request.getInputStream(), "UTF-8", false);
} catch (IOException e) {
jotyMessage(e);
}
return null;
}
/**
* Accepts data identifying the report to be executed, use the BIRT Engine
* for the elaboration of it. On success it returns the 'Report' xml node
* populated with the binary output got from the report engine output
* directory; the 'Report' node is preceded by the 'Result' node positively
* populated.
*
* On failure the output of the call to {@code getResultFromFailure} is
* returned instead.
*
* For the meaning of the parameters here not documented see
* {@link BirtManager#buildReport(String, String, boolean)} method.
*
* @param reportName
* @param formatType
* @param language
* the language so that the suitable report design folder is
* chosen as input context.
* @param twoProcesses
* @return the rendered xml text.
*
* @see BirtManager
*
*/
protected String getReportXml(String reportName, String formatType, String language, boolean twoProcesses) {
StringBuilder retVal = new StringBuilder();
reportManager().setUser(m_user);
reportManager().setPassword(m_password);
reportManager().setLanguage(language);
reportManager().buildReport(reportName, formatType, twoProcesses);
if (reportManager().m_exception == null) {
retVal.append("Ok ");
try {
m_bytes = Utilities.getFileContent( reportManager().outputFileDir() + reportName + "." + formatType,
m_singleByteEncoding
).getBytes(m_singleByteEncoding);
} catch (FileNotFoundException e) {
jotyMessage(e);
} catch (UnsupportedEncodingException e) {
jotyMessage(e);
}
retVal.append(encodedBytes());
retVal.append(" ");
} else
retVal.append(getResultFromFailure(reportManager().m_exception));
return retVal.toString();
}
protected String getResponseFromLogin(String user, String pwd, String query) throws SQLException {
m_user = user;
m_password = pwd;
return getXmlFromDb(query, false, false);
}
protected String getResultFromException(Exception e) {
jotyMessage(e);
return getResultFromFailure(e.getMessage(), (e instanceof SQLException ? String.valueOf(((SQLException) e).getErrorCode()) : ""));
}
protected String getResultFromFailure(String msg) {
return getResultFromFailure(msg, null);
}
protected String getResultFromFailure(String msg, String code) {
StringBuilder retVal = new StringBuilder();
retVal.append("Nok ");
retVal.append(m_xmlEncoder.encode(msg, false));
retVal.append(" ");
retVal.append(code == null ? "" : code);
retVal.append("
");
logUncodedFailureReport(msg);
return retVal.toString();
}
/**
* Basing on the Joty protocol this method builds the xml code corresponding
* to the result received in input and destined to be returned to the client
*
* @param result
* the ResultSet object to be encoded in Joty response.
* @param onlyMetadata
* if true only the 'Structure' xml node is returned (the
* response will contain only the description of the fields o the
* result set)
* @param withBinaries
* if true the binary content of the possible fields of type
* {@code JotyTypes._smallBlobs} is included
* @return the rendered xml text.
* @throws SQLException
*/
protected String getResultSetAsXml(ResultSet result, boolean onlyMetadata, boolean withBinaries) throws SQLException {
StringBuilder retVal = new StringBuilder();
ResultSetMetaData metadata = result.getMetaData();
int colCount = metadata.getColumnCount();
retVal.append("Ok ");
retVal.append("");
int rsetColType;
int size;
int decimals;
int[] types = new int[colCount];
int index;
for (int i = 0; i < colCount; i++) {
index = i + 1;
String name = metadata.getColumnLabel(index);
rsetColType = metadata.getColumnType(index);
size = metadata.getPrecision(index);
decimals = metadata.getScale(index);
String typeName = "";
switch (rsetColType) {
case Types.CHAR:
case Types.VARCHAR:
types[i] = JotyTypes._text;
break;
case Types.FLOAT:
types[i] = JotyTypes._single;
break;
case Types.DOUBLE:
types[i] = JotyTypes._double;
break;
case Types.REAL:
case Types.NUMERIC:
case Types.BIGINT:
if (decimals == 0 || decimals == -127)
if (size > m_intDigitDim)
types[i] = JotyTypes._long;
else
types[i] = JotyTypes._int;
else
types[i] = JotyTypes._double;
break;
case Types.INTEGER:
types[i] = JotyTypes._long;
break;
case Types.SMALLINT:
types[i] = JotyTypes._int;
break;
case 11: // - !
case Types.DATE:
types[i] = JotyTypes._date;
break;
case Types.TIMESTAMP:
types[i] = JotyTypes._dateTime;
break;
case Types.BLOB:
case Types.VARBINARY:
case Types.LONGVARBINARY:
types[i] = m_smallBlobs.get(name) == null ? JotyTypes._blob : JotyTypes._smallBlob;
break;
default:
if (rsetColType == -1 && size > 255 && decimals == 0)
types[i] = JotyTypes._text;
else
types[i] = JotyTypes._none;
;
}
if (types[i] != JotyTypes._none)
typeName = String.valueOf(types[i]);
retVal.append(" ");
}
retVal.append(" ");
if (!onlyMetadata) {
retVal.append("");
String[] openTags = new String[colCount];
String[] closeTags = new String[colCount];
String[] nullTags = new String[colCount];
String[] fields = new String[colCount];
for (int i = 0; i < colCount; i++) {
index = i + 1;
openTags[i] = "";
closeTags[i] = " ";
nullTags[i] = " ";
fields[i] = metadata.getColumnLabel(index);
}
StringBuilder retValB = new StringBuilder();
StringBuilder valueString = new StringBuilder();
SimpleDateFormat format = null;
try {
format = new SimpleDateFormat(getConfStr("xmlDateFormat"));
} catch (ConfigException e) {
retVal.setLength(0);
retVal.append(getResultFromException(e));
}
Date dtVal;
boolean isNull = false;
while (result.next()) {
retValB.append("");
boolean nullValue;
for (int i = 0; i < colCount; i++) {
nullValue = false;
valueString.setLength(0);
if (types[i] == JotyTypes._blob || types[i] == JotyTypes._smallBlob) {
if (withBinaries || types[i] == JotyTypes._smallBlob) {
Blob blob = null;
blob = result.getBlob(fields[i]);
if (blob == null)
nullValue = true;
else {
m_bytes = blob.getBytes(1, (int) (blob.length()));
valueString.append(encodedBytes());
}
} else
valueString.append("0");
} else {
isNull = result.getString(fields[i]) == null || result.getString(fields[i]).isEmpty();
if (isNull)
nullValue = true;
else {
if (types[i] == JotyTypes._date || types[i] == JotyTypes._dateTime) {
if (types[i] == JotyTypes._dateTime) {
result.getTimestamp(fields[i]);
dtVal = new Date(result.getTimestamp(fields[i]).getTime());
} else
dtVal = result.getDate(fields[i]);
valueString.append(format.format(dtVal));
} else
valueString.append(result.getString(fields[i]));
}
}
retValB.append(nullValue ?
nullTags[i] :
(openTags[i] +
((types[i] == JotyTypes._text && !isNull) ?
m_xmlEncoder.encode(valueString.toString(), false) :
valueString) +
closeTags[i])
);
}
retValB.append(" ");
}
retVal.append(retValB);
retVal.append("");
}
return retVal.toString();
}
/**
* From the xml node received in input this method extracts the list of
* {@code Item} objects to be assigned to the {@code BasicPostStatement.m_items}
* member.
*
* @param currNode
* the source xml node-
* @param stnmt
* the target PostStatement object-
*
* @see Item
*/
protected void getStmntItems(Node currNode, PostStatement stnmt) {
Node itemNode = currNode.getFirstChild();
Node itemPart;
String name, val, type;
while (itemNode != null) {
itemPart = itemNode.getFirstChild();
if (itemPart == null)
break;
name = getNodeValue(itemPart, "Name");
itemPart = itemPart.getNextSibling();
val = getNodeValue(itemPart, "Val");
itemPart = itemPart.getNextSibling();
type = getNodeValue(itemPart, "Type");
stnmt.m_items.add(stnmt.new Item(name, val, Integer.parseInt(type)));
itemNode = itemNode.getNextSibling();
}
}
/**
* Executes the sql statetement received in input and encodes the derived
* result set in xml code, basing on the Joty protocol.
*
* @param sqlText
* input sql code.
* @param onlyMetadata
* see {@link getResultSetAsXml}
* @param withBinaries
* " "
* @return the result set encoded in xml
*
* @see #getResultSetAsXml
*/
protected String getXmlFromDb(String sqlText, boolean onlyMetadata, boolean withBinaries) {
String retVal = null;
try {
ResultSet result = m_conn.createStatement().executeQuery(sqlText);
retVal = getResultSetAsXml(result, onlyMetadata, withBinaries);
} catch (SQLException e) {
jotyWarning("Sql : \n " + sqlText);
retVal = getResultFromException(e);
}
return retVal;
}
/**
* Replaces any numbered place holder occurrence with the corresponding element in the vector {@code m_returnedValues}
* @param stmnt the sql statement
* @return the resulting sql text
*/
protected String idSqlSubst(String stmnt) {
if (m_returnedValues.size() == 0)
return stmnt;
else {
String replacedSql = stmnt;
for (int i = 0; i < m_returnedValues.size(); i++)
replacedSql = replacedSql.replace(String.format("'<%1$s%2$d>'", m_genIDtheme, i + 1), m_returnedValues.get(i));
return replacedSql;
}
}
/**
* Executed once, it performs initialization of the JotyServlet instance:
*
* creates server logs, loads configuration content from two different
* configuration file 'ServerSideJoty.xml' and 'JotyServe.xml', either to be
* used on the server side or to be dispatched to the client, loads all the
* language vectors in order to serve any different language request, load
* the proper jdbc driver and prepares it for connections.
*
* If the configuration 'remoteAccessor' item is true the method
* instantiates the application {@code Accessor} object.
*
* On the success of the previously described activities, at last, it creates the
* {@code MethodExecutor}, the {@code ReportManager} and the
* {@code BirtManager} objects (the latter only if the configuration
* 'use_BIRT_engine' item is true)
*
* The method, also, instantiate a {@code DbConnectionGrabber} object the
* methods of which are used along the whole life of the
* servlet .
*
* @see ConfigFile
* @see MethodExecutor
* @see ReportManager
* @see BirtManager
* @see DbConnectionGrabber
*/
@Override
public void init() throws ServletException {
try {
m_debug = true;
m_xmlEncoder = new XmlTextEncoder(this) {
@Override
protected byte[] base64decode(String src) {
return DatatypeConverter.parseBase64Binary(src);
}
@Override
protected String base64encode(byte[] src) {
return DatatypeConverter.printBase64Binary(src);
}};
m_dbLogName = "JotyDbActionLog";
checkHostLogLocation();
m_configuration = new ConfigFile(this, getServletContext().getRealPath("/ServerSideJoty.xml"), true);
m_serverConfig = new ConfigFile(this,getServletContext().getRealPath("/JotyServer.xml"), true);
m_JotyLangs = new CaselessStringKeyMap(this);
m_JotyAppLangs = new CaselessStringKeyMap(this);
m_intDigitDim = getConfInt("intDigitDim");
m_fieldOrdinality = getConfBool("fieldOrdinality");
m_remoteAccessor = getConfBool("remoteAccessor");
m_paginationPageSize = getConfStr("pageSize");
m_dbmsSessionPreset = m_serverConfig.configTermValue("dbmsSessionPreset");
m_paginationQuery = m_serverConfig.configTermValue("selectorStatement");
Utilities.m_encoding = "UTF-8";
loadLanguages();
m_configurationLoaded = m_configuration.m_document != null && m_serverConfig.m_document != null;
if (m_configurationLoaded && checkConfigFileLoading(m_JotyLangs))
checkConfigFileLoading(m_JotyAppLangs);
if (m_configurationLoaded) {
m_debug = getConfBool("debug");
m_logDbActions = getConfBool("logDbActions");
m_shared = getConfBool("shared");
m_sharingKeyField = getConfStr("sharingKeyField");
}
m_errorCarrier = new ErrorCarrier();
responseText();
if (m_configurationLoaded) {
try {
m_dbManager = Instantiator.createDbManager(m_errorCarrier, m_configuration);
} catch (ClassNotFoundException e) {
jotyMessage(e);
}
m_connGrabber = new DbConnectionGrabber() {
@Override
public Connection acquireConnection() throws SQLException, NamingException {
return acquireConnection(false);
}
@Override
public Connection acquireConnection(boolean autoCommit) throws SQLException, NamingException {
return acquireConnection(autoCommit, true);
}
@Override
public Connection acquireConnection(boolean autoCommit, boolean setContainerReference) throws SQLException, NamingException {
Connection retVal = null;
if (! setContainerReference || m_conn == null) {
InitialContext ic;
ic = new InitialContext();
DataSource ds = null;
try {
ds = (DataSource) ic.lookup("java:/comp/env/" + getConfStr("dataSourceName"));
} catch (ConfigException e) {
jotyMessage(e);
}
retVal = ds.getConnection(m_user, m_password);
retVal.setAutoCommit(autoCommit);
if (m_dbmsSessionPreset != null)
retVal.createStatement().execute(m_dbmsSessionPreset);
}
if (setContainerReference)
m_conn = retVal;
return retVal;
}
@Override
public void releaseConnection() {
if (m_conn != null) {
try {
m_conn.close();
} catch (SQLException e) {
jotyMessage(e);
}
m_conn = null;
}
}
};
if (m_remoteAccessor)
try {
m_accessor = Instantiator.createAccessor(this, m_errorCarrier, m_serverConfig, m_configuration, m_connGrabber);
if (m_accessor == null)
jotyWarning("Accessor not specified or not found !");
else {
m_accessor.setPaginationQuery(m_paginationQuery, m_paginationPageSize);
m_accessor.setLangLiteralRetCodeMapper(m_langLiteralRetCodeMapper);
m_queryDefParamContext = new ParamContext(this);
}
} catch (ClassNotFoundException e) {
jotyMessage(e);
}
if (!m_remoteAccessor || m_accessor != null) {
m_methodExecutor = new MethodExecutor(m_accessor, m_errorCarrier, m_returnedValues, m_connGrabber);
m_use_BIRT = getConfBool("use_BIRT_engine");
m_reportManager = new ReportManager();
m_reportManager.setXmlEncoder(m_xmlEncoder);
if (m_use_BIRT) {
String reportsDirectoryName = "/JotyServerReports";
Utilities.checkDirectory(getServletContext().getRealPath(reportsDirectoryName));
m_BirtManager = new BirtManager(m_reportManager);
m_BirtManager.setRealPath(getServletContext().getRealPath(reportsDirectoryName) + "/");
m_BirtManager.init(getConfStr("rptDesignsPath"), getConfStr("rptDocumentsPath"),
getConfStr("rptOutputsPath"), getConfStr("rptLogsPath"));
m_BirtManager.setDbUrl(m_serverConfig.configTermValue("connection-url"));
String jdbcClassName = getConfStr("jdbcDriverClass");
m_msSqlServer = Utilities.isMsSqlServer(jdbcClassName);
m_BirtManager.setJdbcDriverClass(jdbcClassName);
}
}
}
} catch (Exception e) {
jotyMessage(e);
}
super.init();
}
private void checkHostLogLocation() {
if ( ! m_hostLogNameSet) {
Logger.setHostLogName("JotyServerLog", getServletContext().getRealPath("/JotyLogs"));
m_hostLogNameSet = true;
}
}
private String langPath(String lang, String fileName) {
return getServletContext().getRealPath("/lang/" + lang + "/" + fileName);
}
/**
* For each language identifier encountered in the semicolon separated list
* in the configuration item 'languages' the method looks for a language
* folder named like the literal and containing the file jotyLang.xml and
* the file appLang.xml; the former is the dictionary for the Joty framework
* and the latter is the specific dictionary for the application.
* Then load in memory the content of the files.
*
* @throws ConfigException
*/
private void loadLanguages() throws ConfigException {
m_languages = getConfStr("languages");
m_langVector = new Vector();
Utilities.split(m_languages, m_langVector, ";");
ConfigFile mappedConfigFile = null;
ConfigFile configFile = null;
int index = 0;
for (String lang : m_langVector) {
configFile = new ConfigFile(this, langPath(lang, "JotyLang.xml"), true, index == 0 ? lang : null, false);
if (index == 0)
mappedConfigFile = configFile;
m_JotyLangs.put(lang, configFile);
m_JotyAppLangs.put(lang, new ConfigFile(this, langPath(lang, "AppLang.xml"), true));
index++;
}
if (m_langVector.size() > 0) {
m_langLiteralRetCodeMapper = new LangLiteralRetCodeMapper(this);
if (mappedConfigFile.m_document != null)
m_langLiteralRetCodeMapper.load(mappedConfigFile);
} else
jotyWarning("Languages not specified !");
}
private void logUncodedFailureReport(String reason) {
if (m_debug)
jotyWarning("\n Failure report forwarded to the client : \n " + reason);
}
/**
* Makes the PostStatement object members to receive their values by extracting them from the xml node {@code currNode}.
* @param postStatement target PostStatement object
* @param currNode source xml node
*/
void readPostStatement(PostStatement postStatement, Node currNode) {
postStatement.m_sql = getNodeValue(currNode, "SqlStmnt");
currNode = currNode.getNextSibling();
postStatement.m_autoId = getNodeValue(currNode, "AutoId");
currNode = currNode.getNextSibling();
postStatement.m_genTable = getNodeValue(currNode, "GenTable");
currNode = currNode.getNextSibling();
postStatement.m_verifyExpr = getNodeValue(currNode, "VerifyExpr");
currNode = currNode.getNextSibling();
postStatement.m_method = getNodeValue(currNode, "Method");
currNode = currNode.getNextSibling();
postStatement.m_firstOutParamPos = getNodeValue(currNode, "FOPP");
currNode = currNode.getNextSibling();
postStatement.m_outParamsQty = getNodeValue(currNode, "OPQ");
currNode = currNode.getNextSibling();
postStatement.m_AccessorContext = getNodeValue(currNode, "AccessContext");
currNode = currNode.getNextSibling();
postStatement.m_dataPanelIdx = getNodeValue(currNode, "PanelIdx");
currNode = currNode.getNextSibling();
postStatement.m_termName = getNodeValue(currNode, "TermName");
currNode = currNode.getNextSibling();
postStatement.m_mainFilter = getNodeValue(currNode, "MainFilter");
currNode = currNode.getNextSibling();
postStatement.m_sortExpr = getNodeValue(currNode, "SortExpr");
currNode = currNode.getNextSibling();
postStatement.m_iteration = getNodeValue(currNode, "Iteration");
currNode = currNode.getNextSibling();
String attributeNTRA = getNodeValue(currNode, "NMRA");
postStatement.m_nonManagedRollbackActionIden = (attributeNTRA == null || attributeNTRA.length() == 0) ? 0 : Integer.parseInt(attributeNTRA);
if (postStatement.m_nonManagedRollbackActionIden != 0)
currNode = currNode.getNextSibling();
getStmntItems(currNode, postStatement);
}
private void renderError(OutPrinterWrapper wrapper, String reason) {
logUncodedFailureReport(reason);
wrapper.append("Nok " + m_xmlEncoder.encode(reason, false) + " ");
}
private void renderSessExpXml(OutPrinterWrapper wrapper) {
renderError(wrapper, "SESSION_EXP");
}
private void renderSessionID(OutPrinterWrapper wrapper) {
wrapper.append("" + m_sessionID + " ");
}
private void renderXmlFooter(OutPrinterWrapper wrapper) {
renderSessionID(wrapper);
wrapper.append(xmlRootNode(false));
}
private void renderXmlHeader(OutPrinterWrapper wrapper) {
wrapper.append("" + xmlRootNode(true));
}
protected BirtManager reportManager() {
return m_BirtManager;
}
protected boolean rollback() {
boolean retVal = false;
try {
m_conn.rollback();
retVal = true;
} catch (SQLException e) {
jotyMessage(e);
}
return retVal;
}
StringBuilder responseText() {
if (m_responseText==null)
m_responseText = new StringBuilder();
return m_responseText;
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
checkHostLogLocation();
if (m_debug) {
jotyWarning("HTTP" + (request.isSecure() ? "S" : "") + " - " + request.getMethod() + "\n Querystring : \n " + request.getQueryString());
responseText().setLength(0);
}
m_outWriter = response.getWriter();
setNoCacheHeaders(response);
response.setCharacterEncoding("UTF-8");
super.service(request, response);
}
private void setNoCacheHeaders(HttpServletResponse response) {
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "must-revalidate");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Cache-Control", "no-store");
response.setDateHeader("Expires", 0);
}
protected String singleByteEncoding() {
return m_singleByteEncoding;
}
protected String xmlEncodeBinaryContent(String binaryContent) throws Exception {
if (binaryContent == null)
return null;
return m_xmlEncoder.encode(binaryContent, true);
}
private String xmlRootNode(boolean opening) {
return "<" + (opening ? "" : "/") + "JotyResp" +
(m_debug && opening ?
" xmlns='http://www.joty.org' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'" +
" xsi:schemaLocation='http://www.joty.org JotyResponse.xsd' " :
"") +
">";
}
@Override
public void jotyWarning(String text) {
Logger.appendToHostLog(text);
}
@Override
public void jotyMessage(String text) {
jotyWarning(text);
}
@Override
public void jotyMessage(Throwable t) {
Logger.throwableToHostLog(t);
}
@Override
public void jotyMessage(Exception e) {
Logger.exceptionToHostLog(e);
}
@Override
public void ASSERT(boolean predicate) {
if (m_debug && !predicate)
Logger.stackTraceToHostLog("ASSERTION VIOLATED");
}
@Override
public boolean isDesignTime() {
return false;
}
@Override
public void afterReportRender(String arg0) {
}
@Override
public void beforeReportRender() {
}
}