/* * Created on 25.11.2003 * * (c) Stabsstelle IKT-Strategie des Bundes */ package at.gv.egovernment.moa.ss.erechtclient.servlets; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Properties; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; 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 org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.log4j.Logger; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import at.gv.egovernment.moa.ss.erechtclient.ERechtClientException; import at.gv.egovernment.moa.ss.erechtclient.init.Constants; import at.gv.egovernment.moa.ss.erechtclient.moainvoker.MOAInvoker; import at.gv.egovernment.moa.ss.erechtclient.moainvoker.RequestBuilder; import at.gv.egovernment.moa.ss.erechtclient.util.DOMUtils; import at.gv.egovernment.moa.ss.erechtclient.util.Utils; import at.gv.egovernment.moa.ss.erechtclient.util.XPathUtils; /** * @author Gregor Karlinger (mailto:gregor.karlinger@cio.gv.at) */ public class Dispatcher extends HttpServlet { private static Logger logger_ = Logger.getLogger(Constants.LH_SERVLETS_); private static final String XPATH_ALL_IMGS_ = "//" + Constants.NSPRE_XMLBGBL_ + ":" + Constants.XML_LN_XMLBGBL_IMG_; private static final String FN_XMLBGBL_ = "xMLBGBl"; private static final String FN_STYLESHEET_ = "stylesheet"; private static final String FN_IMAGE_ = "image."; private static final String FN_XMLSIG_ = "signature"; private static final String TS_XMLBGBL_ = "xml"; private static final String TS_STYLESHEET_ = "xsl"; private static final String TS_IMAGE_ = "img"; private static final String TS_XMLSIG_ = "xml"; private static final String LN_XMLSIG_ = "Signature"; private static final String LN_SIGENV_ = "SignatureEnvironment"; public Dispatcher() { super(); } /* ---------------------------------------------------------------------------------------------------- */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { try { String screenName = request.getServletPath(); if (Constants.SRVN_UPLOAD_XML_.equals(screenName)) { // Invalidate session if one exist from a previous use of the web application HttpSession session = ((HttpServletRequest) request).getSession(false); if (session != null) session.invalidate(); RequestDispatcher dispatcher = request.getRequestDispatcher(Constants.JSPPN_UPLOAD_XML_); dispatcher.forward(request, response); } else { String message = "Unproper use of servlet \"" + screenName + "\". Please start with servlet \"" + Constants.SRVN_UPLOAD_XML_ + "\"."; throw new ERechtClientException(message); } } catch (Exception e) { Utils.returnErrorPage(request, response, e); } } /* ---------------------------------------------------------------------------------------------------- */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException { try { String screenName = request.getServletPath(); if (Constants.SRVN_UPLOAD_XML_.equals(screenName)) { // Evaluate uploaded XML BGBl HttpSession session = request.getSession(true); // Read BGBl XML upload from POST request List params = parseParameters(request); FileItem xMLBGBlFI = getFileItem(Constants.FPN_UPLOAD_XML_XMLBGBL_, params); String xMLBGBlFileName = saveFileItem(xMLBGBlFI, FN_XMLBGBL_, TS_XMLBGBL_, session.getId(), this.getServletContext()); session.setAttribute(Constants.SCP_XMLBGBL_FNAME_, xMLBGBlFileName); // Read stylesheet upload from POST request FileItem stylesheetFI = getFileItem(Constants.FPN_UPLOAD_STYLESHEET_, params); if (stylesheetFI.getName() != null && !"".equals(stylesheetFI.getName().trim())) { // Stylesheet has been uploaded String stylesheetFileName = saveFileItem(stylesheetFI, FN_STYLESHEET_, TS_STYLESHEET_, session.getId(), this.getServletContext()); session.setAttribute(Constants.SCP_STYLESHEET_FNAME_, stylesheetFileName); } // Scan BGBl XML for potential images Document xMLBGBlDoc = parseXMLBGBlDocument(xMLBGBlFileName, this.getServletContext()); ArrayList imageNames = scanXMLBGBlForImages(xMLBGBlDoc); if (!imageNames.isEmpty()) { // Images exist in the BGBl XML, therefore continue with image upload session.setAttribute(Constants.SCP_IMAGE_NAMES_LIST_, imageNames); RequestDispatcher dispatcher = request.getRequestDispatcher(Constants.JSPPN_UPLOAD_IMG_); dispatcher.forward(request, response); return; } else { // Indicate with empty List in session that there are no images available session.setAttribute(Constants.SCP_IMAGES_LIST_, new ArrayList(0)); } } else if (Constants.SRVN_UPLOAD_IMG_.equals(screenName)) { HttpSession session = ((HttpServletRequest) request).getSession(false); if (session == null) { String message = "Could not read session object."; throw new ERechtClientException(message); } List images = parseImageParameters(request, this.getServletContext()); session.setAttribute(Constants.SCP_IMAGES_LIST_, images); } else { String message = "Unproper use of servlet \"" + screenName + "\". Please start with servlet \"" + Constants.SRVN_UPLOAD_XML_ + "\"."; logger_.error(message); throw new ERechtClientException(message); } // Create and store signature HttpSession session = request.getSession(false); Document signatureResponse = createXMLSignature(request, session); String signatureFileName = saveXMLSignature(signatureResponse, session.getId(), this.getServletContext()); Properties initProps = (Properties) this.getServletContext().getAttribute(Constants.WSCP_INIT_PROPS_); String webAppHostPortFromMOASS = Utils.readInitProperty(initProps, Constants.IP_WEBAPP_HOST_PORT_FROM_MOA_SS_, logger_); session.setAttribute(Constants.SCP_SIGNATURE_URL_, webAppHostPortFromMOASS + request.getContextPath() + signatureFileName); // Dispatch Download JSP page RequestDispatcher dispatcher = request.getRequestDispatcher(Constants.JSPPN_DOWNLOAD_SIG_); dispatcher.forward(request, response); } catch (Exception e) { Utils.returnErrorPage(request, response, e); } } private Document createXMLSignature(HttpServletRequest request, HttpSession session) throws ERechtClientException { RequestBuilder requestBuilder = new RequestBuilder(this.getServletContext(), request.getContextPath()); String xMLBGBlFileName = (String) session.getAttribute(Constants.SCP_XMLBGBL_FNAME_); if (xMLBGBlFileName == null) { String message = "Could not read XML BGBl file name from session."; logger_.error(message); throw new ERechtClientException(message); } requestBuilder.setXMLDocument(xMLBGBlFileName); String stylesheetFileName = (String) session.getAttribute(Constants.SCP_STYLESHEET_FNAME_); if (stylesheetFileName != null) { requestBuilder.setStylesheet(stylesheetFileName); } else { requestBuilder.useDefaultStylesheet(); } List images = (List) session.getAttribute(Constants.SCP_IMAGES_LIST_); if (images == null) { String message = "Could not read images from session."; logger_.error(message); throw new ERechtClientException(message); } Iterator imagesIt = images.iterator(); while (imagesIt.hasNext()) { Image currImg = (Image) imagesIt.next(); requestBuilder.addImage(currImg.name_, currImg.fileLocation_); } Document signatureRequest = requestBuilder.getRequest(); Properties initProps = (Properties) this.getServletContext().getAttribute(Constants.WSCP_INIT_PROPS_); String serviceEndpoint = Utils.readInitProperty(initProps, Constants.IP_SS_ENDPOINT_, logger_); String mOASchemaLoc = Utils.readInitProperty(initProps, Constants.IP_MOA_SCHEMA_, logger_); String webAppHostPort = Utils.readInitProperty(initProps, Constants.IP_WEBAPP_HOST_PORT_, logger_); Document signatureResponse = MOAInvoker.invokeSS(signatureRequest, serviceEndpoint, "file:" + this.getServletContext().getRealPath(mOASchemaLoc)); return signatureResponse; } private List parseImageParameters(HttpServletRequest request, ServletContext context) throws ERechtClientException { HttpSession session = request.getSession(false); if (session == null) { String message = "Could not read session object."; throw new ERechtClientException(message); } ArrayList imageNames = (ArrayList) session.getAttribute(Constants.SCP_IMAGE_NAMES_LIST_); List params = parseParameters(request); ArrayList images = new ArrayList(imageNames.size()); for (int i = 0; i < params.size(); i++) { FileItem currItem = (FileItem) params.get(i); if (currItem.getFieldName().startsWith(Constants.FPN_UPLOAD_IMG_IMG_)) { if (currItem.getSize() <= 0) { String message = "No content received for image \"" + currItem.getFieldName() + "\"."; logger_.error(message); throw new ERechtClientException(message); } String imgFileName = saveFileItem(currItem, FN_IMAGE_ + images.size(), TS_IMAGE_, session.getId(), context); images.add(new Image(currItem.getFieldName().substring(Constants.FPN_UPLOAD_IMG_IMG_.length()), imgFileName)); } } // Check if there is a file item for each image name if (imageNames.size() != images.size()) { String message = "No correct number of immages has been uploaded (Expected " + imageNames.size() + ", actually received " + images.size() + ")."; logger_.error(message); throw new ERechtClientException(message); } return images; } private Document parseXMLBGBlDocument(String docFileName, ServletContext context) throws ERechtClientException { // TODO Change to validating parsing? // DOMParser xmlParser = (DOMParser) context.getAttribute(Constants.WSCP_XMLPARSER_); // InputSource docInputSource = new InputSource(docIS); Document parsedDoc = null; try { // xmlParser.parse(docInputSource); FileInputStream docIS = new FileInputStream(context.getRealPath(docFileName)); parsedDoc = DOMUtils.parseWellFormed(docIS); } catch (Exception e) { String message = "Parsing XML BGBl document failed."; logger_.error(message, e); throw new ERechtClientException(message, e); } Element docElem = parsedDoc.getDocumentElement(); if (docElem.getNamespaceURI() != Constants.NSURI_XMLBGBL_ || docElem.getLocalName() != Constants.XML_LN_XMLBGBL_ROOT_) { String message = "XML BGBl has wrong root element (Local name equals \"" + docElem.getLocalName() + "\", NS-URI equals \"" + docElem.getNamespaceURI() + "\")."; logger_.error(message); throw new ERechtClientException(message); } return parsedDoc; } private ArrayList scanXMLBGBlForImages(Document xMLBGBlDoc) throws ERechtClientException { // Get all bka:binary elements in XML BGBl document NodeList imgElems; try { XPathUtils xpUtils = new XPathUtils(); String additionalNSPrefixes = Constants.NSPRE_XMLBGBL_ + " " + Constants.NSURI_XMLBGBL_; xpUtils.setupContext(XPATH_ALL_IMGS_, xMLBGBlDoc.getDocumentElement(), additionalNSPrefixes); imgElems = xpUtils.selectNodeSet(xMLBGBlDoc); } catch (Exception e) { String message = "Scanning for image elements in XML BGBl failed."; logger_.error(message, e); throw new ERechtClientException(message, e); } // Collect the file refs of all bka:binary elements (either in bka:binary/@ref or in bka:binary/bka:src) ArrayList list = new ArrayList(imgElems.getLength()); for (int i = 0; i < imgElems.getLength(); i++) { Element currElem = (Element) imgElems.item(i); Attr refAttr = currElem.getAttributeNodeNS(null, Constants.XML_LN_XMLBGBL_IMG_REF_); if (refAttr != null) { list.add(i, refAttr.getValue()); } else { list.add(DOMUtils.getChildText(currElem, Constants.NSURI_XMLBGBL_, Constants.XML_LN_XMLBGBL_IMG_SRC_)); } } return list; } private List parseParameters(HttpServletRequest request) throws ERechtClientException { if (ServletFileUpload.isMultipartContent(request)) { // Request is encoded as multipart/form-data List items; try { FileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = null;; upload = new ServletFileUpload(factory); items = upload.parseRequest(request); return items; } catch (FileUploadException e) { String message = "Parsing HTML form parameter failed."; logger_.error(message, e); throw new ERechtClientException(message, e); } } else { // Request must be encoded als multipart/form-data throw new ERechtClientException("HTML form encoding is not mulitpart/form-data."); } } private FileItem getFileItem(String fileItemName, List fileItemParams) { Iterator iter = fileItemParams.iterator(); while (iter.hasNext()) { FileItem currentFI = (FileItem) iter.next(); if (currentFI.getFieldName().equals(fileItemName)) return currentFI; } return null; } private String saveFileItem(FileItem fileItem, String name, String typeSuffix, String sessionId, ServletContext context) throws ERechtClientException { Properties initProps = (Properties) this.getServletContext().getAttribute(Constants.WSCP_INIT_PROPS_); String tempDir = Utils.readInitProperty(initProps, Constants.IP_TEMP_DIR_, logger_); String fileName = tempDir + sessionId + "." + name + "." + typeSuffix; String realFileName = context.getRealPath(fileName); try { fileItem.write(new File(realFileName)); } catch (Exception e) { String message = "Writing item \"" + name + "\" to file system failed."; logger_.error(message, e); throw new ERechtClientException(message, e); } return fileName; } private String saveXMLSignature(Document mOAResponse, String sessionId, ServletContext context) throws ERechtClientException { Element sigEnvElem = DOMUtils.getChildElem(mOAResponse.getDocumentElement(), Constants.NSURI_MOA_13_, LN_SIGENV_); Element signatureElem = DOMUtils.getChildElem(sigEnvElem, Constants.NSURI_DSIG_, LN_XMLSIG_); Properties initProps = (Properties) this.getServletContext().getAttribute(Constants.WSCP_INIT_PROPS_); String tempDir = Utils.readInitProperty(initProps, Constants.IP_TEMP_DIR_, logger_); String fileName = tempDir + sessionId + "." + FN_XMLSIG_ + "." + TS_XMLSIG_; String realFileName = context.getRealPath(fileName); try { FileOutputStream fileOS = new FileOutputStream(realFileName); MOAInvoker.serializeElement(signatureElem, fileOS); fileOS.close(); } catch (Exception e) { String message = "Writing xml signature to file system failed."; logger_.error(message, e); throw new ERechtClientException(message, e); } return fileName; } class Image { public String name_; public String fileLocation_; public Image(String name, String fileLocation) { name_ = name; fileLocation_ = fileLocation; } } }