All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.enhydra.xml.xmlc.misc.SSIReader Maven / Gradle / Ivy

The newest version!
/*
 * Enhydra Java Application Server Project
 * 
 * The contents of this file are subject to the Enhydra Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License on
 * the Enhydra web site ( http://www.enhydra.org/ ).
 * 
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 
 * the License for the specific terms governing rights and limitations
 * under the License.
 * 
 * The Initial Developer of the Enhydra Application Server is Lutris
 * Technologies, Inc. The Enhydra Application Server and portions created
 * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
 * All Rights Reserved.
 * 
 * Contributor(s):
 * 
 * $Id: SSIReader.java,v 1.8 2005/02/14 02:09:24 taweili Exp $
 */

package org.enhydra.xml.xmlc.misc;

import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.net.URL;

import org.xml.sax.InputSource;

//FIXME: Keeping the LineNumberMap maybe inefficient.  We might want to
//drop this in favor of just tracking the current line number (and maybe
//one back.  Need to see how the parser behaves.  Plus, with this class
//reading everything into memory, we could just lines when actually
//needed.  Also, all of the line number map stuff isn't abstracted.

/**
 * A reader that implements Server-Side Includes (SSI).  This used the syntax
 * defined by Apache mod_include, however it only implements the `include'
 * directive.
 * 

* This input stream automatically closes on reaching EOF. */ public final class SSIReader extends Reader { /** * Listener for SSI open/close events. */ public class Listener { /** Classed when a new include file is opened. */ } /** * Include command and arguments. */ private static final String INCLUDE = "include"; private static final String INCLUDE_FILE = "file"; private static final String INCLUDE_VIRTUAL = "virtual"; private static final String[] INCLUDE_VALID_ARGS = { INCLUDE_FILE, INCLUDE_VIRTUAL }; /** * The ssi-base set */ private String ssiBase = null; /** * Input stream we are reading from. Also the top of the stack, * if others have been included. */ private SSIParsedStream fIn; /** * Map of stream position to source file and line number. */ private LineNumberRecorder fLineNumbers; /** * Construct a new reader for the specified file. */ //public SSIReader(InputSource source) throws IOException { public SSIReader(InputSource source, String ssiBase) throws IOException { fLineNumbers = new LineNumberRecorder(); fIn = new SSIParsedStream(source, fLineNumbers); this.ssiBase = ssiBase; } /** * Get the system id of the currently opened file. */ public String getSystemId() { if (fIn != null) { return fIn.getSystemId(); } else { return null; } } /** * Open a SSI include file, pushing on the stack. */ private void openSSIInclude(String includingFileName, String fileName) throws IOException { // Get path to file, relative to source directory if (ssiBase != null) { // The following maybe written better, but I think // SSI-syntax needs the leading slash, so it should work. if (fileName.startsWith("/")) { fileName = ssiBase + File.separator + fileName; } } String systemId = ""; try { File includingFile = new File(includingFileName); includingFile. getCanonicalPath(); //Fail fast (IOException) if we are dealing with a URL File inclFile = new File(fileName); File baseDir = null; if (!inclFile.isAbsolute()) { baseDir = includingFile.getParentFile(); } File inclPath = new File(baseDir, fileName); systemId = inclPath.toString(); // Problem with toURL().getExternalForm(). It returns strange URL } catch (IOException ioe) { try { String baseDir = ""; if (!fileName.startsWith("/")) { //TODO - revisit! This tries to mimick the above, //but what would this mean for the "file:" //protocol? Where would "/index.ssi" be located //when there is no domain name to be relative to //in the "file:" protocol? The URL would be //invalid. And we aren't getting a "file:" //protocol on the fileName itself. Unless this is //re-written, we only support relative SSI's and //this check is a bit pointless. baseDir = includingFileName.substring(0, includingFileName.lastIndexOf("/") + 1); } URL url = new URL(baseDir + fileName); systemId = url.toExternalForm(); } catch (IOException ioe2) { throw ioe2; } } // Open new reader, push current one fIn = new SSIParsedStream(new InputSource(systemId), fLineNumbers, fIn); } /** * Process a SSI include directive. */ private void processSSIInclude(SSIDirective directive) throws IOException { // Validate directive.validateArgumentNames(INCLUDE_VALID_ARGS); if (directive.getNumArgs() < 1) { throw new IOException("SSI include must have at least one argument"); } // Open includes. Done in reverse, as they are pushed on a stack for (int idx = directive.getNumArgs()-1; idx >= 0; idx--) { openSSIInclude(directive.getSystemId(), directive.getArgValue(idx)); } } /** * Process the SSI directive that is next in the stream. */ private void processSSIDirective() throws IOException { SSIDirective directive = fIn.parseSSIDirective(); if (directive.getCmd().equals(INCLUDE)) { processSSIInclude(directive); } else { throw new IOException("Invalid or unsupport SSI command \"" + directive.getCmd() + "\": " + fIn.getSystemId()); } } /** * Read a character. * @return The character, -1 if no more characters are available. */ public int read() throws IOException { int ch; do { ch = fIn.read(); if (ch == SSIParsedStream.AT_EOF) { fIn = fIn.pop(); if (fIn == null) { return -1; // EOF } } else if (ch == SSIParsedStream.AT_SSI) { processSSIDirective(); } } while (ch < 0); return ch; } /** * Read characters into a portion of an array. To simplify the * handling of an SSI directive, a directive is only processed if * it's at the start of the buffer. SSIs in the middle of the * read result in a partial read. * * @see java.io.FilterReader#read * @exception IOException If an I/O error occurs */ public int read(char cbuf[], int off, int len) throws IOException { int readLen; do { readLen = fIn.read(cbuf, off, len); if (readLen == SSIParsedStream.AT_EOF) { fIn = fIn.pop(); if (fIn == null) { return -1; // EOF } } else if (readLen == SSIParsedStream.AT_SSI) { // Directive might change fIn to a new file. processSSIDirective(); } } while (readLen < 0); return readLen; } /** * Close the stream. * * @exception IOException If an I/O error occurs */ public void close() throws IOException { fIn = null; } /** * Get the line number map. */ public final LineNumberMap getLineNumberMap() { return fLineNumbers; } /** * Construct an InputSource containing an SSI reader. */ // dbr_20020128.4_start //public static InputSource create(InputSource inputSource) throws IOException { public static InputSource create(InputSource inputSource, String ssiBase) throws IOException { InputSource ssiSource //= new InputSource(new SSIReader(inputSource)); = new InputSource(new SSIReader(inputSource, ssiBase)); // dbr_20020128.4_end ssiSource.setPublicId(inputSource.getPublicId()); ssiSource.setSystemId(inputSource.getSystemId()); ssiSource.setEncoding(inputSource.getEncoding()); return ssiSource; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy