protected boolean handleIncludeElement()

in src/org/apache/xerces/xinclude/XIncludeHandler.java [1457:1822]


    protected boolean handleIncludeElement(XMLAttributes attributes)
        throws XNIException {
        if (getSawInclude(fDepth - 1)) {
            reportFatalError("IncludeChild", new Object[] { XINCLUDE_INCLUDE });
        }
        if (getState() == STATE_IGNORE) {
            return true;
        }
        setSawInclude(fDepth, true);
        fNamespaceContext.setContextInvalid();

        // TODO: does Java use IURIs by default?
        //       [Definition: An internationalized URI reference, or IURI, is a URI reference that directly uses [Unicode] characters.]
        // TODO: figure out what section 4.1.1 of the XInclude spec is talking about
        //       has to do with disallowed ASCII character escaping
        //       this ties in with the above IURI section, but I suspect Java already does it
        
        String href = attributes.getValue(XINCLUDE_ATTR_HREF);
        String parse = attributes.getValue(XINCLUDE_ATTR_PARSE);
        String xpointer =  attributes.getValue(XPOINTER);
        String accept = attributes.getValue(XINCLUDE_ATTR_ACCEPT);
        String acceptLanguage = attributes.getValue(XINCLUDE_ATTR_ACCEPT_LANGUAGE);
        
        if (parse == null) {
            parse = XINCLUDE_PARSE_XML;
        }
        if (href == null) {
            href = XMLSymbols.EMPTY_STRING;
        }
        if (href.length() == 0 && XINCLUDE_PARSE_XML.equals(parse)) {
            if (xpointer == null) {
                reportFatalError("XpointerMissing");
            }
            else {
                // When parse="xml" and an xpointer is specified treat 
                // all absences of the href attribute as a resource error.
                Locale locale = (fErrorReporter != null) ? fErrorReporter.getLocale() : null;
                String reason = fXIncludeMessageFormatter.formatMessage(locale, "XPointerStreamability", null);
                reportResourceError("XMLResourceError", new Object[] { href, reason });
                return false;
            }
        }

        URI hrefURI = null;
        
        // Check whether href is correct and perform escaping as per section 4.1.1 of the XInclude spec.
        // Report fatal error if the href value contains a fragment identifier or if the value after
        // escaping is a syntactically invalid URI or IRI.
        try {
            hrefURI = new URI(href, true);
            if (hrefURI.getFragment() != null) {
                reportFatalError("HrefFragmentIdentifierIllegal", new Object[] {href});
            }
        }
        catch (URI.MalformedURIException exc) {
            String newHref = escapeHref(href);
            if (href != newHref) {
                href = newHref;
                try {
                    hrefURI = new URI(href, true);
                    if (hrefURI.getFragment() != null) {
                        reportFatalError("HrefFragmentIdentifierIllegal", new Object[] {href});
                    }
                }
                catch (URI.MalformedURIException exc2) {
                    reportFatalError("HrefSyntacticallyInvalid", new Object[] {href});
                }
            }
            else {
                reportFatalError("HrefSyntacticallyInvalid", new Object[] {href});
            }
        }
        
        // Verify that if an accept and/or an accept-language attribute exist
        // that the value(s) don't contain disallowed characters.
        if (accept != null && !isValidInHTTPHeader(accept)) {
            reportFatalError("AcceptMalformed", null);
            accept = null;
        }
        if (acceptLanguage != null && !isValidInHTTPHeader(acceptLanguage)) {
            reportFatalError("AcceptLanguageMalformed", null);
            acceptLanguage = null;
        }

        XMLInputSource includedSource = null;
        if (fEntityResolver != null) {
            try {
                XMLResourceIdentifier resourceIdentifier =
                    new XMLResourceIdentifierImpl(
                        null,
                        href,
                        fCurrentBaseURI.getExpandedSystemId(),
                        XMLEntityManager.expandSystemId(
                            href,
                            fCurrentBaseURI.getExpandedSystemId(),
                            false));

                includedSource =
                    fEntityResolver.resolveEntity(resourceIdentifier);
                
                if (includedSource != null &&
                    !(includedSource instanceof HTTPInputSource) &&
                    (accept != null || acceptLanguage != null) &&
                    includedSource.getCharacterStream() == null &&
                    includedSource.getByteStream() == null) {
                    
                    includedSource = createInputSource(includedSource.getPublicId(), includedSource.getSystemId(), 
                        includedSource.getBaseSystemId(), accept, acceptLanguage);
                }
            }
            catch (IOException e) {
                reportResourceError(
                    "XMLResourceError",
                    new Object[] { href, e.getMessage()}, e);
                return false;
            }
        }

        if (includedSource == null) {
            // setup an HTTPInputSource if either of the content negotation attributes were specified.
            if (accept != null || acceptLanguage != null) {
                includedSource = createInputSource(null, href, fCurrentBaseURI.getExpandedSystemId(), accept, acceptLanguage);
            }
            else {
                includedSource = new XMLInputSource(null, href, fCurrentBaseURI.getExpandedSystemId());
            }
        }
        
        if (parse.equals(XINCLUDE_PARSE_XML)) {
            // Instead of always creating a new configuration, the first one can be reused
            if ((xpointer != null && fXPointerChildConfig == null) 
            		|| (xpointer == null && fXIncludeChildConfig == null) ) {
            	
            	String parserName = XINCLUDE_DEFAULT_CONFIGURATION;
            	if (xpointer != null)
            		parserName = "org.apache.xerces.parsers.XPointerParserConfiguration";
            	
                fChildConfig =
                    (XMLParserConfiguration)ObjectFactory.newInstance(
                        parserName,
                        ObjectFactory.findClassLoader(),
                        true);

                // use the same symbol table, error reporter, entity resolver, security manager and buffer size.
                if (fSymbolTable != null) fChildConfig.setProperty(SYMBOL_TABLE, fSymbolTable);
                if (fErrorReporter != null) fChildConfig.setProperty(ERROR_REPORTER, fErrorReporter);
                if (fEntityResolver != null) fChildConfig.setProperty(ENTITY_RESOLVER, fEntityResolver);
                fChildConfig.setProperty(SECURITY_MANAGER, fSecurityManager);
                fChildConfig.setProperty(BUFFER_SIZE, new Integer(fBufferSize));
                
                // features must be copied to child configuration
                fNeedCopyFeatures = true;

                // use the same namespace context
                fChildConfig.setProperty(
                    Constants.XERCES_PROPERTY_PREFIX
                        + Constants.NAMESPACE_CONTEXT_PROPERTY,
                    fNamespaceContext);

                fChildConfig.setFeature(
                            XINCLUDE_FIXUP_BASE_URIS,
                            fFixupBaseURIs);

                fChildConfig.setFeature(
                            XINCLUDE_FIXUP_LANGUAGE,
                            fFixupLanguage);
                
               
                // If the xpointer attribute is present
                if (xpointer != null ) {
                	
                    XPointerHandler newHandler =
                        (XPointerHandler)fChildConfig.getProperty(
                            Constants.XERCES_PROPERTY_PREFIX
                                + Constants.XPOINTER_HANDLER_PROPERTY);

                	fXPtrProcessor = newHandler;

                	// ???
                	((XPointerHandler)fXPtrProcessor).setProperty(
                            Constants.XERCES_PROPERTY_PREFIX
                            + Constants.NAMESPACE_CONTEXT_PROPERTY,
                        fNamespaceContext);

                    ((XPointerHandler)fXPtrProcessor).setProperty(XINCLUDE_FIXUP_BASE_URIS,
                            fFixupBaseURIs ? Boolean.TRUE : Boolean.FALSE);

                    ((XPointerHandler)fXPtrProcessor).setProperty(
                            XINCLUDE_FIXUP_LANGUAGE,
                            fFixupLanguage ? Boolean.TRUE : Boolean.FALSE);
                    
                    if (fErrorReporter != null) 
                    	((XPointerHandler)fXPtrProcessor).setProperty(ERROR_REPORTER, fErrorReporter);
                	// ???
                    
                    newHandler.setParent(this); 
                    newHandler.setHref(href);
                    newHandler.setXIncludeLocator(fXIncludeLocator);
                    newHandler.setDocumentHandler(this.getDocumentHandler());
                    fXPointerChildConfig = fChildConfig;                       
                } else {
                    XIncludeHandler newHandler =
                        (XIncludeHandler)fChildConfig.getProperty(
                            Constants.XERCES_PROPERTY_PREFIX
                                + Constants.XINCLUDE_HANDLER_PROPERTY);

                    newHandler.setParent(this);
                    newHandler.setHref(href);
                    newHandler.setXIncludeLocator(fXIncludeLocator);
                    newHandler.setDocumentHandler(this.getDocumentHandler());
                    fXIncludeChildConfig = fChildConfig;
                }
            }

            // If an xpointer attribute is present
            if (xpointer != null ) {
            	fChildConfig = fXPointerChildConfig;
            	
                // Parse the XPointer expression
                try {
                    ((XPointerProcessor)fXPtrProcessor).parseXPointer(xpointer);
                    
                } catch (XNIException ex) {
                    // report the XPointer error as a resource error
                    reportResourceError(
                            "XMLResourceError",
                            new Object[] { href, ex.getMessage()});
                        return false;
                }
            } else {
            	fChildConfig = fXIncludeChildConfig;
            }

            // set all features on parserConfig to match this parser configuration
            if (fNeedCopyFeatures) {
                copyFeatures(fSettings, fChildConfig);
            }
            fNeedCopyFeatures = false;

            try {
                fHasIncludeReportedContent = false;
                fNamespaceContext.pushScope();

                fChildConfig.parse(includedSource);
                // necessary to make sure proper location is reported to the application and in errors
                fXIncludeLocator.setLocator(fDocLocation);
                if (fErrorReporter != null) {
                    fErrorReporter.setDocumentLocator(fDocLocation);
                }

                // If the xpointer attribute is present
                if (xpointer != null ) { 
                	// and it was not resolved
                	if (!((XPointerProcessor)fXPtrProcessor).isXPointerResolved()) {
                        Locale locale = (fErrorReporter != null) ? fErrorReporter.getLocale() : null;
                        String reason = fXIncludeMessageFormatter.formatMessage(locale, "XPointerResolutionUnsuccessful", null);
                        reportResourceError("XMLResourceError", new Object[] {href, reason});
                		// use the fallback
                		return false;
                	}
                }
            }
            catch (XNIException e) {
                // necessary to make sure proper location is reported to the application and in errors
                fXIncludeLocator.setLocator(fDocLocation);
                if (fErrorReporter != null) {
                    fErrorReporter.setDocumentLocator(fDocLocation);
                }
                reportFatalError("XMLParseError", new Object[] { href });
            }
            catch (IOException e) {
                // necessary to make sure proper location is reported to the application and in errors
                fXIncludeLocator.setLocator(fDocLocation);
                if (fErrorReporter != null) {
                    fErrorReporter.setDocumentLocator(fDocLocation);
                }
                // If the start document event has been seen on the child pipeline it
                // means the resource was successfully opened and we started reporting
                // document events. If an IOException is thrown after the start document
                // event we had a failure midstream and cannot recover.
                if (fHasIncludeReportedContent) {
                    throw new XNIException(e);
                }
                // In other circumstances an IOException indicates that we had trouble 
                // accessing or opening the file, not that it was an invalid XML file. So we 
                // send a resource error, not a fatal error.
                reportResourceError(
                    "XMLResourceError",
                    new Object[] { href, e.getMessage()}, e);
                return false;
            }
            finally {
                fNamespaceContext.popScope();
            }
        }
        else if (parse.equals(XINCLUDE_PARSE_TEXT)) {
            // we only care about encoding for parse="text"
            String encoding = attributes.getValue(XINCLUDE_ATTR_ENCODING);
            includedSource.setEncoding(encoding);
            XIncludeTextReader textReader = null;
            
            try {
                fHasIncludeReportedContent = false;
                
                // Setup the appropriate text reader.
                if (!fIsXML11) {
                    if (fXInclude10TextReader == null) {
                        fXInclude10TextReader = new XIncludeTextReader(includedSource, this, fBufferSize);
                    }
                    else {
                        fXInclude10TextReader.setInputSource(includedSource);
                    }
                    textReader = fXInclude10TextReader;
                }
                else {
                    if (fXInclude11TextReader == null) {
                        fXInclude11TextReader = new XInclude11TextReader(includedSource, this, fBufferSize);
                    }
                    else {
                        fXInclude11TextReader.setInputSource(includedSource);
                    }
                    textReader = fXInclude11TextReader;
                }
                textReader.setErrorReporter(fErrorReporter);
                textReader.parse();
            }
            // encoding errors
            catch (MalformedByteSequenceException ex) {
                fErrorReporter.reportError(ex.getDomain(), ex.getKey(), 
                    ex.getArguments(), XMLErrorReporter.SEVERITY_FATAL_ERROR, ex);
            }
            catch (CharConversionException e) {
                fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
                    "CharConversionFailure", null, XMLErrorReporter.SEVERITY_FATAL_ERROR, e);
            }
            catch (IOException e) {
                // If a characters event has already been sent down the pipeline it
                // means the resource was successfully opened and that this IOException
                // is from a failure midstream from which we cannot recover.
                if (fHasIncludeReportedContent) {
                    throw new XNIException(e);
                }
                reportResourceError(
                    "TextResourceError",
                    new Object[] { href, e.getMessage()}, e);
                return false;
            }
            finally {
                if (textReader != null) {
                    try {
                        textReader.close();
                    }
                    catch (IOException e) {
                        reportResourceError(
                            "TextResourceError",
                            new Object[] { href, e.getMessage()}, e);
                        return false;
                    }
                }
            }
        }
        else {
            reportFatalError("InvalidParseValue", new Object[] { parse });
        }
        return true;
    }