stephan 2002/08/09 00:30:31 Added: src/scratchpad/src/org/apache/cocoon/components/source/impl BlobSource.java BlobSourceFactory.java Log: BlobSource rewritten to use the Excalibur Source classes. Revision Changes Path 1.1 xml-cocoon2/src/scratchpad/src/org/apache/cocoon/components/source/impl/BlobSource.java Index: BlobSource.java =================================================================== /* * The Apache Software License, Version 1.1 * * * Copyright (c) 2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache Cocoon" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.cocoon.components.source.impl; import org.apache.avalon.excalibur.datasource.DataSourceComponent; import org.apache.avalon.framework.component.ComponentException; import org.apache.avalon.framework.component.ComponentManager; import org.apache.avalon.framework.component.ComponentSelector; import org.apache.avalon.framework.component.Composable; import org.apache.avalon.framework.logger.AbstractLogEnabled; import org.apache.excalibur.source.Source; import org.apache.excalibur.source.SourceException; import org.apache.excalibur.source.SourceValidity; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.io.ByteArrayInputStream; import java.io.FilterInputStream; import java.net.MalformedURLException; import java.util.Iterator; import java.sql.*; /** * A <code>Source</code> that takes its content in a single JDBC column. Any * kind of column can be used (clob, blob, varchar, etc), but "Blob" means * that the whole content is contained in a single column. * <p>The URL syntax is "blob:/datasource/table/column[cond]", where : * <ul> * <li>"datasource" is the jdbc datasource to use (defined in cocoon.xonf) * <li>"table" is the database table, * <li>"column" is (you can guess, now :) the column in "table", * <li>"cond" is the boolean condition used to select a particular record in * the table. * </ul> * <p>For example, "<code>blob:/personel/people/photo[userid='foo']</code>" * will fetch the first column returned by the statement "<code>SELECT photo * from people where userid='foo'</code>" in the datasource "<code>personel</code>" * * @author <a href="mailto:[EMAIL PROTECTED]">Sylvain Wallez</a> * @author <a href="mailto:[EMAIL PROTECTED]">Stephan Michels</a> * @version $Id: BlobSource.java,v 1.1 2002/08/09 07:30:31 stephan Exp $ */ public class BlobSource extends AbstractLogEnabled implements Source, Composable { /** The component manager instance */ private ComponentManager manager = null; /** * The system ID for this source */ private String systemId; private String datasourceName; private String tableName; private String columnName; private String condition; private final static String URL_PREFIX = "blob:/"; private final static int URL_PREFIX_LEN = URL_PREFIX.length(); /** * Create a file source from a 'blob:' url and a component manager. * <p>The url is of the form "blob:/datasource/table/column[condition] */ public BlobSource(String url) throws MalformedURLException { this.systemId = url; // Parse the url int start = URL_PREFIX_LEN; int end; // Datasource end = url.indexOf('/', start); if (end == -1) { throw new MalformedURLException("Malformed blob source (cannot find datasource) : " + url); } this.datasourceName = url.substring(start, end); // Table start = end + 1; end = url.indexOf('/', start); if (end == -1) { throw new MalformedURLException("Malformed blob source (cannot find table name) : " + url); } this.tableName = url.substring(start, end); // Column start = end + 1; end = url.indexOf('[', start); if (end == -1) { this.columnName = url.substring(start); } else { this.columnName = url.substring(start, end); // Condition start = end + 1; end = url.length() - 1; if (url.charAt(end) != ']') { throw new MalformedURLException("Malformed url for a blob source (cannot find condition) : " + url); } else { this.condition = url.substring(start, end); } } } /** * Set the current <code>ComponentManager</code> instance used by this * <code>Composable</code>. */ public void compose(ComponentManager manager) throws ComponentException { this.manager = manager; } /** * Return the unique identifer for this source */ public String getSystemId() { return this.systemId; } /** * Get the input stream for this source. */ public InputStream getInputStream() throws IOException, SourceException { if (getLogger().isDebugEnabled()) { getLogger().debug("Opening stream for datasource " + this.datasourceName + ", table " + this.tableName + ", column " + this.columnName + (this.condition == null ? ", no condition" : ", condition " + this.condition) ); } Connection cnx = null; Statement stmt = null; try { cnx = getConnection(); stmt = cnx.createStatement(); StringBuffer selectBuf = new StringBuffer("SELECT ").append(this.columnName). append(" FROM ").append(this.tableName); if (this.condition != null) { selectBuf.append(" WHERE ").append(this.condition); } String select = selectBuf.toString(); if (getLogger().isDebugEnabled()) { getLogger().debug("Executing statement " + select); } ResultSet rs = stmt.executeQuery(select); rs.next(); int colType = rs.getMetaData().getColumnType(1); switch(colType) { case Types.BLOB : Blob blob = rs.getBlob(1); return new JDBCInputStream(blob.getBinaryStream(), cnx); //break; case Types.CLOB : Clob clob = rs.getClob(1); return new JDBCInputStream(clob.getAsciiStream(), cnx); //break; default : String value = rs.getString(1); stmt.close(); rs.close(); cnx.close(); return new ByteArrayInputStream(value.getBytes()); } } catch(SQLException sqle) { String msg = "Cannot retrieve content from " + this.systemId; getLogger().error(msg, sqle); try { if (cnx != null) { cnx.close(); } } catch(SQLException sqle2) { // PITA throw new SourceException("Cannot close connection", sqle2); } // IOException would be more adequate, but ProcessingException is cascaded... throw new SourceException(msg, sqle); } } /** * Get the Validity object. This can either wrap the last modification * date or the expires information or... * If it is currently not possible to calculate such an information * <code>null</code> is returned. */ public SourceValidity getValidity() { return null; } /** * Refresh the content of this object after the underlying data * content has changed. */ public void discardValidity() { } /** * The mime-type of the content described by this object. * If the source is not able to determine the mime-type by itself * this can be <code>null</code>. */ public String getMimeType() { return null; } /** * Return the content length of the content or -1 if the length is * unknown */ public long getContentLength() { return -1; } /** * Get the last modification date. * @return The last modification in milliseconds since January 1, 1970 GMT * or 0 if it is unknown */ public long getLastModified() { return 0; } /** * Get the value of a parameter. * Using this it is possible to get custom information provided by the * source implementation, like an expires date, HTTP headers etc. */ public String getParameter(String name) { return null; } /** * Get the value of a parameter. * Using this it is possible to get custom information provided by the * source implementation, like an expires date, HTTP headers etc. */ public long getParameterAsLong(String name) { return 0; } /** * Get parameter names * Using this it is possible to get custom information provided by the * source implementation, like an expires date, HTTP headers etc. */ public Iterator getParameterNames() { return new EmptyIterator(); } class EmptyIterator implements Iterator { public boolean hasNext() { return false; } public Object next() { return null; } public void remove() {} } private Connection getConnection() throws SourceException { ComponentSelector selector = null; DataSourceComponent datasource = null; try { try { selector = (ComponentSelector)this.manager.lookup(DataSourceComponent.ROLE + "Selector"); datasource = (DataSourceComponent)selector.select(this.datasourceName); } catch(Exception e) { String msg = "Cannot get datasource '" + this.datasourceName + "'"; getLogger().error(msg); throw new SourceException(msg, e); } try { return datasource.getConnection(); } catch(Exception e) { String msg = "Cannot get connection for datasource '" + this .datasourceName + "'"; getLogger().error(msg); throw new SourceException(msg, e); } } finally { if (datasource != null) { selector.release(datasource); } } } /** * An OutputStream that will close the connection that created it on * close. */ private class JDBCInputStream extends FilterInputStream { Connection cnx; private final void closeCnx() throws IOException { if (this.cnx != null) { try { Connection tmp = cnx; cnx = null; tmp.close(); } catch(Exception e) { String msg = "Error closing the connection for " + BlobSource.this.systemId; BlobSource.this.getLogger().error(msg, e); throw new IOException(msg + " : " + e.getMessage()); } } } public JDBCInputStream(InputStream stream, Connection cnx) { super(stream); this.cnx = cnx; } public int read() throws IOException { try { int result = in.read(); if (result == -1) { closeCnx(); } return result; } catch(IOException e) { closeCnx(); throw e; } } public int read(byte[] b) throws IOException { try { int result = in.read(b); if (result == -1) { closeCnx(); } return result; } catch(IOException e) { closeCnx(); throw e; } } public int read(byte[] b, int off, int len) throws IOException { try { int result = in.read(b, off, len); if (result == -1) { closeCnx(); } return result; } catch(IOException e) { closeCnx(); throw e; } } public void close() throws IOException { super.close(); closeCnx(); } } } 1.1 xml-cocoon2/src/scratchpad/src/org/apache/cocoon/components/source/impl/BlobSourceFactory.java Index: BlobSourceFactory.java =================================================================== /* * The Apache Software License, Version 1.1 * * * Copyright (c) 2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache Cocoon" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.cocoon.components.source.impl; import org.apache.avalon.framework.thread.ThreadSafe; import org.apache.excalibur.source.Source; import org.apache.excalibur.source.SourceException; import org.apache.excalibur.source.SourceFactory; import java.io.IOException; import java.net.MalformedURLException; import java.util.Map; /** * A factory for 'blob:' sources. * * @author <a href="mailto:[EMAIL PROTECTED]">Sylvain Wallez</a> * @author <a href="mailto:[EMAIL PROTECTED]">Stephan Michels</a> * @version $Id: BlobSourceFactory.java,v 1.1 2002/08/09 07:30:31 stephan Exp $ */ public class BlobSourceFactory implements SourceFactory, ThreadSafe { /** * Get a <code>Source</code> object. * @param parameters This is optional. */ public Source getSource(String location, Map parameters) throws MalformedURLException, IOException, SourceException { return new BlobSource(location); } }
---------------------------------------------------------------------- In case of troubles, e-mail: [EMAIL PROTECTED] To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]