private Stage2CacheableState readStaticState( PipelineContext pipelineContext, ExternalContext externalContext, IndentedLogger indentedLogger, XFormsStaticState[] staticState) { final StaticStateBits staticStateBits = new StaticStateBits(pipelineContext, externalContext, indentedLogger, null); { final XFormsStaticState cachedState = XFormsStaticStateCache.instance() .getDocument(pipelineContext, staticStateBits.staticStateDigest); if (cachedState != null && cachedState.getMetadata().checkBindingsIncludes()) { // Found static state in cache indentedLogger.logDebug("", "found up-to-date static state by digest in cache"); staticState[0] = cachedState; } else { // Not found static state in cache OR it is out of date, create and initialize static state // object // NOTE: In out of date case, could clone static state and reprocess instead? if (cachedState != null) indentedLogger.logDebug("", "found out-of-date static state by digest in cache"); else indentedLogger.logDebug("", "did not find static state by digest in cache"); staticState[0] = new XFormsStaticState( pipelineContext, staticStateBits.staticStateDocument, staticStateBits.staticStateDigest, staticStateBits.metadata); // Store in cache XFormsStaticStateCache.instance().storeDocument(pipelineContext, staticState[0]); } } // Update input dependencies object return new Stage2CacheableState( staticStateBits.annotatedTemplate, staticStateBits.staticStateDigest); }
/** * Restore an XFormsContainingDocument from XFormsState only. * * <p>Used by XFormsStateManager. * * @param xformsState XFormsState containing static and dynamic state * @param disableUpdates whether to disable updates (for recreating initial document upon browser * back) */ public XFormsContainingDocument(XFormsState xformsState, boolean disableUpdates) { super(); // 1. Restore the static state { final scala.Option<String> staticStateDigest = xformsState.staticStateDigest(); if (staticStateDigest.isDefined()) { final XFormsStaticState cachedState = XFormsStaticStateCache.instance().getDocument(staticStateDigest.get()); if (cachedState != null) { // Found static state in cache indentedLogger().logDebug("", "found static state by digest in cache"); this.staticState = cachedState; } else { // Not found static state in cache, create static state from input indentedLogger().logDebug("", "did not find static state by digest in cache"); indentedLogger().startHandleOperation("initialization", "restoring static state"); this.staticState = XFormsStaticStateImpl.restore(staticStateDigest, xformsState.staticState()); indentedLogger().endHandleOperation(); // Store in cache XFormsStaticStateCache.instance().storeDocument(this.staticState); } assert this.staticState.isServerStateHandling(); } else { // Not digest provided, create static state from input indentedLogger().logDebug("", "did not find static state by digest in cache"); this.staticState = XFormsStaticStateImpl.restore(staticStateDigest, xformsState.staticState()); assert this.staticState.isClientStateHandling(); } this.staticOps = new StaticStateGlobalOps(staticState.topLevelPart()); this.xpathDependencies = Version.instance().createUIDependencies(this); this.supportUpdates = !disableUpdates && !isNoUpdates(); } // 2. Restore the dynamic state indentedLogger().startHandleOperation("initialization", "restoring containing document"); try { restoreDynamicState(xformsState.dynamicState()); } catch (Exception e) { throw OrbeonLocationException.wrapException( e, new ExtendedLocationData(null, "re-initializing XForms containing document")); } indentedLogger().endHandleOperation(); }
/** * Create an XFormsContainingDocument from an XFormsStaticState object. * * <p>Used by XFormsToXHTML. * * @param staticState static state object * @param uriResolver URIResolver for loading instances during initialization (and possibly more, * such as schemas and "GET" submissions upon initialization) * @param response optional response for handling replace="all" during initialization */ public XFormsContainingDocument( XFormsStaticState staticState, XFormsURIResolver uriResolver, ExternalContext.Response response) { super(); // Create UUID for this document instance this.uuid = SecureUtils.randomHexId(); // Initialize request information { initializeRequestInformation(); initializePathMatchers(); } indentedLogger() .startHandleOperation( "initialization", "creating new ContainingDocument (static state object provided).", "uuid", this.uuid); { // Remember static state this.staticState = staticState; this.staticOps = new StaticStateGlobalOps(staticState.topLevelPart()); // NOTE: template is not stored right away, as it depends on the evaluation of the noscript // property. this.xpathDependencies = Version.instance().createUIDependencies(this); // Whether we support updates // NOTE: Reading the property requires the static state set above this.supportUpdates = !isNoUpdates(); // Remember parameters used during initialization this.uriResolver = uriResolver; this.response = response; this.initializing = true; // Initialize the containing document try { initialize(); } catch (Exception e) { throw OrbeonLocationException.wrapException( e, new ExtendedLocationData(null, "initializing XForms containing document")); } } indentedLogger().endHandleOperation(); }
@Override public Scope innerScope() { // Do it here because at construction time, we don't yet have access to the static state! return staticState.topLevelPart().startScope(); }
@Override public PartAnalysis partAnalysis() { return staticState.topLevelPart(); }
private void gatherInputDependencies( PipelineContext pipelineContext, XFormsContainingDocument containingDocument, IndentedLogger indentedLogger, Stage1CacheableState stage1CacheableState) { final String forwardSubmissionHeaders = XFormsProperties.getForwardSubmissionHeaders(containingDocument); // Add static instance source dependencies for top-level models // TODO: check all models/instances final XFormsStaticState staticState = containingDocument.getStaticState(); for (final Model model : staticState.getModelsForScope(staticState.getXBLBindings().getTopLevelScope())) { for (final Instance instance : model.instancesMap().values()) { if (instance.dependencyURL() != null) { final String resolvedDependencyURL = XFormsUtils.resolveServiceURL( pipelineContext, containingDocument, instance.element(), instance.dependencyURL(), ExternalContext.Response.REWRITE_MODE_ABSOLUTE); if (!instance.isCacheHint()) { stage1CacheableState.addReference( null, resolvedDependencyURL, instance.xxformsUsername(), instance.xxformsPassword(), instance.xxformsPassword(), forwardSubmissionHeaders); if (indentedLogger.isDebugEnabled()) indentedLogger.logDebug( "", "adding document cache dependency for non-cacheable instance", "instance URI", resolvedDependencyURL); } else { // Don't add the dependency as we don't want the instance URI to be hit // For all practical purposes, globally shared instances must remain constant! if (indentedLogger.isDebugEnabled()) indentedLogger.logDebug( "", "not adding document cache dependency for cacheable instance", "instance URI", resolvedDependencyURL); } } } } // Set caching dependencies if the input was actually read // TODO: check all models/instances // Q: should use static dependency information instead? what about schema imports and instance // replacements? for (final XFormsModel currentModel : containingDocument.getModels()) { // Add schema dependencies final String[] schemaURIs = currentModel.getSchemaURIs(); // TODO: We should also use dependencies computed in XFormsModelSchemaValidator.SchemaInfo if (schemaURIs != null) { for (final String currentSchemaURI : schemaURIs) { if (indentedLogger.isDebugEnabled()) indentedLogger.logDebug( "", "adding document cache dependency for schema", "schema URI", currentSchemaURI); stage1CacheableState.addReference( null, currentSchemaURI, null, null, null, forwardSubmissionHeaders); // TODO: support username / password on schema refs } } } // TODO: Add @src attributes from controls? Not used often. // Set caching dependencies for XBL inclusions { final XFormsStaticState.Metadata metadata = containingDocument.getStaticState().getMetadata(); final Set<String> includes = metadata.getBindingsIncludes(); if (includes != null) { for (final String include : includes) { stage1CacheableState.addReference(null, "oxf:" + include, null, null, null, null); } } } }
private void doIt( final PipelineContext pipelineContext, XMLReceiver xmlReceiver, final URIProcessorOutputImpl processorOutput, String outputName) { final ExternalContext externalContext = XFormsUtils.getExternalContext(pipelineContext); final IndentedLogger indentedLogger = XFormsContainingDocument.getIndentedLogger( XFormsToXHTML.logger, XFormsServer.getLogger(), LOGGING_CATEGORY); // ContainingDocument and XFormsState created below final XFormsContainingDocument[] containingDocument = new XFormsContainingDocument[1]; final boolean[] cachedStatus = new boolean[] {false}; final Stage2CacheableState stage2CacheableState; if (TEST_STATE == null) { // Read and try to cache the complete XForms+XHTML document with annotations stage2CacheableState = (Stage2CacheableState) readCacheInputAsObject( pipelineContext, getInputByName(INPUT_ANNOTATED_DOCUMENT), new CacheableInputReader() { public Object read( PipelineContext pipelineContext, ProcessorInput processorInput) { // Compute annotated XForms document + static state document final Stage1CacheableState stage1CacheableState = new Stage1CacheableState(); final Stage2CacheableState stage2CacheableState; final XFormsStaticState[] staticState = new XFormsStaticState[1]; { // Store dependencies container in state before reading ((Stage2TransientState) XFormsToXHTML.this.getState(pipelineContext)) .stage1CacheableState = stage1CacheableState; // Read static state from input stage2CacheableState = readStaticState( pipelineContext, externalContext, indentedLogger, staticState); } // Create containing document and initialize XForms engine // NOTE: Create document here so we can do appropriate analysis of caching // dependencies final XFormsURIResolver uriResolver = new XFormsURIResolver( XFormsToXHTML.this, processorOutput, pipelineContext, INPUT_ANNOTATED_DOCUMENT, URLGenerator.DEFAULT_HANDLE_XINCLUDE); containingDocument[0] = new XFormsContainingDocument( pipelineContext, staticState[0], stage2CacheableState.getAnnotatedTemplate(), uriResolver); // Gather set caching dependencies gatherInputDependencies( pipelineContext, containingDocument[0], indentedLogger, stage1CacheableState); return stage2CacheableState; } @Override public void foundInCache() { cachedStatus[0] = true; } }, false); TEST_STATE = DO_TEST_STATE ? stage2CacheableState : null; } else { stage2CacheableState = TEST_STATE; } try { // Create containing document if not done yet if (containingDocument[0] == null) { assert cachedStatus[0]; // In this case, we found the static state digest and more in the cache, but we must now // create a new XFormsContainingDocument from this information indentedLogger.logDebug( "", "annotated document and static state digest obtained from cache", "digest", stage2CacheableState.getStaticStateDigest()); final XFormsStaticState staticState; { final XFormsStaticState cachedState = XFormsStaticStateCache.instance() .getDocument(pipelineContext, stage2CacheableState.getStaticStateDigest()); if (cachedState != null && cachedState.getMetadata().checkBindingsIncludes()) { // Found static state in cache indentedLogger.logDebug("", "found up-to-date static state by digest in cache"); staticState = cachedState; } else { // Not found static state in cache OR it is out of date, create static state from input // NOTE: In out of date case, could clone static state and reprocess instead? if (cachedState != null) indentedLogger.logDebug("", "found out-of-date static state by digest in cache"); else indentedLogger.logDebug("", "did not find static state by digest in cache"); final StaticStateBits staticStateBits = new StaticStateBits( pipelineContext, externalContext, indentedLogger, stage2CacheableState.getStaticStateDigest()); staticState = new XFormsStaticState( pipelineContext, staticStateBits.staticStateDocument, stage2CacheableState.getStaticStateDigest(), staticStateBits.metadata); // Store in cache XFormsStaticStateCache.instance().storeDocument(pipelineContext, staticState); } } final XFormsURIResolver uriResolver = new XFormsURIResolver( XFormsToXHTML.this, processorOutput, pipelineContext, INPUT_ANNOTATED_DOCUMENT, URLGenerator.DEFAULT_HANDLE_XINCLUDE); containingDocument[0] = new XFormsContainingDocument( pipelineContext, staticState, stage2CacheableState.getAnnotatedTemplate(), uriResolver); } else { assert !cachedStatus[0]; indentedLogger.logDebug( "", "annotated document and static state digest not obtained from cache."); } // Output resulting document if (outputName.equals("document")) { // Normal case where we output XHTML outputResponseDocument( pipelineContext, externalContext, indentedLogger, stage2CacheableState.getAnnotatedTemplate(), containingDocument[0], xmlReceiver); } else { // Output in test mode testOutputResponseState( pipelineContext, containingDocument[0], indentedLogger, xmlReceiver); } // Notify state manager XFormsStateManager.instance().afterInitialResponse(pipelineContext, containingDocument[0]); } catch (Throwable e) { indentedLogger.logDebug("", "throwable caught during initialization."); throw new OXFException(e); } }