/** * Copyright (C) 2010 Orbeon, Inc. * * This program 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 * 2.1 of the License, or (at your option) any later version. * * This program 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. * * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html */ package org.orbeon.oxf.xforms.submission; import org.orbeon.oxf.externalcontext.ExternalContext; import org.orbeon.oxf.externalcontext.ResponseWrapper; import org.orbeon.oxf.util.ConnectionResult; import org.orbeon.oxf.util.NetUtils; import org.orbeon.oxf.xforms.XFormsContainingDocument; import org.orbeon.oxf.xforms.event.events.ErrorType$; import org.orbeon.oxf.xforms.event.events.XFormsSubmitErrorEvent; import java.io.IOException; import java.io.OutputStream; /** * Handle replace="all". */ public class AllReplacer extends BaseReplacer { public AllReplacer(XFormsModelSubmission submission, XFormsContainingDocument containingDocument) { super(submission, containingDocument); } public void deserialize(ConnectionResult cxr, SubmissionParameters p, SecondPassParameters p2) { // NOP } public Runnable replace(ConnectionResult cxr, SubmissionParameters p, SecondPassParameters p2) throws IOException { // When we get here, we are in a mode where we need to send the reply directly to an external context, if any. // Remember that we got a submission producing output containingDocument.setGotSubmissionReplaceAll(); final ReplaceAllResponse replaceAllResponse = new ReplaceAllResponse(containingDocument.getResponse()); forwardResultToResponse(cxr, replaceAllResponse); // Success: "the event xforms-submit-done may be dispatched with appropriate context information" // Error: "either the document is replaced with an implementation-specific indication of an error or submission // processing concludes after dispatching xforms-submit-error with appropriate context information, including an // error-type of resource-error" if (! p.isDeferredSubmissionSecondPass()) { if (NetUtils.isSuccessCode(cxr.statusCode())) return submission.sendSubmitDone(cxr); else // Here we dispatch xforms-submit-error upon getting a non-success error code, even though the response has // already been written out. This gives the form author a chance to do something in cases the response is // buffered, for example do a sendError(). throw new XFormsSubmissionException(submission, "xf:submission for submission id: " + submission.getId() + ", error code received when submitting instance: " + cxr.statusCode(), "processing submission response", new XFormsSubmitErrorEvent(submission, ErrorType$.MODULE$.RESOURCE_ERROR(), cxr)); } else { // Two reasons: 1. We don't want to modify the document state 2. This can be called outside of the document // lock, see XFormsServer. return null; } } public static void forwardResultToResponse(ConnectionResult cxr, final ExternalContext.Response response) throws IOException { if (response == null) return; // can be null for some unit tests only :( response.setStatus(cxr.statusCode()); if (cxr.content().contentType().isDefined()) response.setContentType(cxr.content().contentType().get()); SubmissionUtils.forwardResponseHeaders(cxr, response); // Forward content to response final OutputStream outputStream = response.getOutputStream(); try { NetUtils.copyStream(cxr.content().inputStream(), outputStream); } finally { cxr.close(); } // End document and close outputStream.flush(); outputStream.close(); } public static class ReplaceAllResponse extends ResponseWrapper { private int status = -1; // indicate that status was not set public ReplaceAllResponse(ExternalContext.Response response) { super(response); } @Override public void setStatus(int status) { assert status > 0; this.status = status; super.setStatus(status); } public int getStatus() { return status; } } }