sylvain 2003/04/04 08:36:52
Modified: sourceresolve build.xml
sourceresolve/src/java/org/apache/excalibur/source
ModifiableTraversableSource.java
MoveableSource.java SourceFactory.java
SourceParameters.java SourceUtil.java
TraversableSource.java
sourceresolve/src/java/org/apache/excalibur/source/impl
FileSource.java ResourceSource.java
SourceResolverImpl.java URLSource.java
URLSourceFactory.java
Added: sourceresolve/src/java/org/apache/excalibur/source/impl
FileSourceFactory.java
sourceresolve/src/test/org/apache/excalibur/source/test
FileSourceTestCase.java
SourceResolverImplTestCase.java
SourceUtilTestCase.java
Removed: sourceresolve/src/test/org/apache/excalibur/source
SourceResolverImplTestCase.java
Log:
- simplify TraversableSource
- make FileSource implement it
- simplify URLSource and URLSourceFactory
- scheme extraction methods in SourceUtil
- lots of clean up
- some unit tests
Revision Changes Path
1.31 +1 -5 avalon-excalibur/sourceresolve/build.xml
Index: build.xml
===================================================================
RCS file: /home/cvs/avalon-excalibur/sourceresolve/build.xml,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -r1.30 -r1.31
--- build.xml 24 Mar 2003 20:42:35 -0000 1.30
+++ build.xml 4 Apr 2003 16:36:51 -0000 1.31
@@ -177,17 +177,13 @@
<formatter type="xml"/> <!-- xml reports for junitreport -->
<formatter type="plain" usefile="false"/> <!-- text reports for humans
-->
- <!-- added the next line because the standard approach does not seem to
be working -->
- <test name="org.apache.excalibur.source.SourceResolverImplTestCase"
todir="${build.tests}"/>
-
- <!--
<batchtest todir="${build.tests}">
<fileset dir="${build.testclasses}">
<include name="**/test/*TestCase.class"/>
<exclude name="**/Abstract*"/>
</fileset>
</batchtest>
- -->
+
</junit>
</target>
1.2 +4 -4
avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/ModifiableTraversableSource.java
Index: ModifiableTraversableSource.java
===================================================================
RCS file:
/home/cvs/avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/ModifiableTraversableSource.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ModifiableTraversableSource.java 29 Jan 2003 06:56:01 -0000 1.1
+++ ModifiableTraversableSource.java 4 Apr 2003 16:36:51 -0000 1.2
@@ -64,13 +64,13 @@
public interface ModifiableTraversableSource extends ModifiableSource,
TraversableSource
{
/**
- * If it doesn't already exist, create the directory corresponding to this
source
+ * If it doesn't already exist, ensure this source is traversable
* (equivalent to <code>File.mkdirs()</code>)
* <p>
* If the source already exists, this method does nothing if it's already
- * a directory, and fails otherwise.
+ * traversable, and fails otherwise.
*/
- public void makeDirectory() throws SourceException;
+ public void makeCollection() throws SourceException;
}
1.3 +3 -3
avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/MoveableSource.java
Index: MoveableSource.java
===================================================================
RCS file:
/home/cvs/avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/MoveableSource.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- MoveableSource.java 25 Feb 2003 16:28:51 -0000 1.2
+++ MoveableSource.java 4 Apr 2003 16:36:51 -0000 1.3
@@ -75,7 +75,7 @@
* @throws SourceException If an exception occurs during
* the copy.
*/
- void copy(Source destination) throws SourceException;
+ void copyTo(Source destination) throws SourceException;
/**
* Move the current source to a specified destination.
@@ -85,5 +85,5 @@
* @throws SourceException If an exception occurs during
* the move.
*/
- void move(Source source) throws SourceException;
+ void moveTo(Source source) throws SourceException;
}
1.8 +3 -2
avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/SourceFactory.java
Index: SourceFactory.java
===================================================================
RCS file:
/home/cvs/avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/SourceFactory.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- SourceFactory.java 29 Mar 2003 18:53:26 -0000 1.7
+++ SourceFactory.java 4 Apr 2003 16:36:51 -0000 1.8
@@ -55,6 +55,7 @@
package org.apache.excalibur.source;
import java.io.IOException;
+import java.net.MalformedURLException;
import java.util.Map;
import org.apache.avalon.framework.component.Component;
@@ -93,7 +94,7 @@
* @throws IOException if the source couldn't be created for some reason.
*/
Source getSource( String location, Map parameters )
- throws IOException;
+ throws IOException, MalformedURLException;
/**
* Release a [EMAIL PROTECTED] Source} object.
1.6 +3 -2
avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/SourceParameters.java
Index: SourceParameters.java
===================================================================
RCS file:
/home/cvs/avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/SourceParameters.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- SourceParameters.java 29 Jan 2003 06:56:01 -0000 1.5
+++ SourceParameters.java 4 Apr 2003 16:36:51 -0000 1.6
@@ -73,7 +73,8 @@
* <p>
* Only particular kinds of <code>Source</code> implementations, such as
* [EMAIL PROTECTED] org.apache.excalibur.source.impl.URLSource} support this kind
of
- * parameters, passed as an entry in the <code>parameters</code> argument of
+ * parameters, passed as the [EMAIL PROTECTED] SourceResolver#URI_PARAMETERS} entry
+ * in the <code>parameters</code> argument of
* [EMAIL PROTECTED] SourceResolver#resolveURI(String, String, Map)}.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Carsten Ziegeler</a>
1.6 +120 -13
avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/SourceUtil.java
Index: SourceUtil.java
===================================================================
RCS file:
/home/cvs/avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/SourceUtil.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- SourceUtil.java 30 Jan 2003 07:57:10 -0000 1.5
+++ SourceUtil.java 4 Apr 2003 16:36:51 -0000 1.6
@@ -344,7 +344,7 @@
if (source instanceof MoveableSource
&& source.getClass().equals(destination.getClass()))
{
- ((MoveableSource)source).move(destination);
+ ((MoveableSource)source).moveTo(destination);
}
else if (source instanceof ModifiableSource)
{
@@ -356,6 +356,101 @@
throw new SourceException("Source '"+source.getURI()+ "' is not
writeable");
}
}
+
+ /**
+ * Get the position of the scheme-delimiting colon in an absolute URI, as
specified
+ * by <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>, appendix A.
This method is
+ * primarily useful for [EMAIL PROTECTED] Source} implementors that want to
separate
+ * the scheme part from the specific part of an URI.
+ * <p>
+ * Use this method when you need both the scheme and the scheme-specific part
of an URI,
+ * as calling successively [EMAIL PROTECTED] #getScheme(String)} and [EMAIL
PROTECTED] #getSpecificPart(String)}
+ * will call this method twice, and as such won't be efficient.
+ *
+ * @param uri the URI
+ * @return int the scheme-delimiting colon, or <code>-1</code> if not found.
+ */
+ public static int indexOfSchemeColon(String uri)
+ {
+ // absoluteURI = scheme ":" ( hier_part | opaque_part )
+ //
+ // scheme = alpha *( alpha | digit | "+" | "-" | "." )
+ //
+ // alpha = lowalpha | upalpha
+ //
+ // lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
+ // "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
+ // "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
+ //
+ // upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
+ // "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
+ // "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
+ //
+ // digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
+ // "8" | "9"
+
+ // Must have at least one character followed by a colon
+ if (uri == null || uri.length() < 2)
+ {
+ return -1;
+ }
+
+ // Check that first character is alpha
+ // (lowercase first since it's the most common case)
+ char ch = uri.charAt(0);
+ if ( (ch < 'a' || ch > 'z') &&
+ (ch < 'A' || ch > 'Z') )
+ {
+ // Invalid first character
+ return -1;
+ }
+
+ int pos = uri.indexOf(':');
+ if (pos != -1)
+ {
+ // Check that every character before the colon is in the allowed range
+ // (the first one was tested above)
+ for (int i = 1; i < pos; i++)
+ {
+ ch = uri.charAt(i);
+ if ( (ch < 'a' || ch > 'z') &&
+ (ch < 'A' || ch > 'Z') &&
+ (ch < '0' || ch > '9') &&
+ ch != '+' && ch != '-' && ch != '.')
+ {
+ return -1;
+ }
+ }
+ }
+
+ return pos;
+ }
+
+ /**
+ * Get the scheme of an absolute URI.
+ *
+ * @param uri the absolute URI
+ * @return the URI scheme
+ */
+ public static String getScheme(String uri)
+ {
+ int pos = indexOfSchemeColon(uri);
+ return (pos == -1) ? null : uri.substring(0, pos);
+ }
+
+ /**
+ * Get the scheme-specific part of an absolute URI. Note that this includes
everything
+ * after the separating colon, including the fragment, if any (RFC 2396
separates it
+ * from the scheme-specific part).
+ *
+ * @param uri the absolute URI
+ * @return the scheme-specific part of the URI
+ */
+ public static String getSpecificPart(String uri)
+ {
+ int pos = indexOfSchemeColon(uri);
+ return (pos == -1) ? null : uri.substring(pos+1);
+ }
/**
* Copy the source to a specified destination.
@@ -372,7 +467,7 @@
if (source instanceof MoveableSource
&& source.getClass().equals(destination.getClass()))
{
- ((MoveableSource) source).copy(destination);
+ ((MoveableSource) source).copyTo(destination);
}
else
{
@@ -385,16 +480,8 @@
try {
OutputStream out = ((ModifiableSource)
destination).getOutputStream();
InputStream in = source.getInputStream();
-
- byte[] buffer = new byte[8192];
- int length = -1;
-
- while ((length = in.read(buffer))>-1) {
- out.write(buffer, 0, length);
- }
- in.close();
- out.flush();
- out.close();
+
+ copy(in, out);
} catch (IOException ioe) {
throw new SourceException("Could not copy source '"+
source.getURI()+"' to '"+
@@ -402,6 +489,26 @@
ioe.getMessage(), ioe);
}
}
+ }
+
+ /**
+ * Copy the contents of an <code>InputStream</code> to an
<code>OutputStream</code>.
+ *
+ * @param in
+ * @param out
+ * @throws IOException
+ */
+ static public void copy(InputStream in, OutputStream out) throws IOException
+ {
+ byte[] buffer = new byte[8192];
+ int length = -1;
+
+ while ((length = in.read(buffer))>-1) {
+ out.write(buffer, 0, length);
+ }
+ in.close();
+ out.flush();
+ out.close();
}
}
1.4 +24 -35
avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/TraversableSource.java
Index: TraversableSource.java
===================================================================
RCS file:
/home/cvs/avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/TraversableSource.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- TraversableSource.java 29 Jan 2003 06:56:01 -0000 1.3
+++ TraversableSource.java 4 Apr 2003 16:36:51 -0000 1.4
@@ -68,54 +68,44 @@
public interface TraversableSource extends Source {
/**
- * Does this source point to a directory (i.e. it possibly has children) ?
+ * Is this source a collection, i.e. it possibly has children ?
+ * For a filesystem-based implementation, this would typically mean that
+ * this source represents a directory and not a file.
*
- * @return true if the source is a directory.
+ * @return true if the source exists and is traversable.
*/
- boolean isDirectory();
-
- /**
- * Get the absolute URIs of the children of this source.
- *
- * @return a possibly-empty collection if this source is a directory,
- * <code>null</code> otherwise
- * @throws SourceException if some problem occurs.
- */
- Collection getChildrenURIs() throws SourceException;
+ boolean isCollection();
/**
- * Get the children of this source as [EMAIL PROTECTED] Source} objects.
+ * Get the children of this source if this source is traversable.
* <p>
* <em>Note:</em> only those sources actually fetched from the
* collection need to be released using the [EMAIL PROTECTED] SourceResolver}.
*
- * @return a possibly-empty collection if this source is a directory,
- * <code>null</code> otherwise
- * @throws SourceException if some problem occurs.
+ * @see #isTraversable()
+ * @return a collection of [EMAIL PROTECTED] Source}s (actually most probably
<code>TraversableSource</code>s).
+ * @throws SourceException this source is not traversable, or if some problem
occurs.
*/
- Collection getChildrenSources() throws SourceException;
+ Collection getChildren() throws SourceException;
/**
- * Get the children of this source as relative names.
- * @return a possibly-empty collection if this source is a directory,
- * <code>null</code> otherwise
- * @throws SourceException if some problem occurs.
+ * Get a child of this source, given its name. Note that the returned source
+ * may not actually physically exist, and that this must be checked using
+ * [EMAIL PROTECTED] Source#exists()}.
+ *
+ * @param name the child name.
+ * @return the child source.
+ * @throws SourceException if this source is not traversable or if some other
+ * error occurs.
*/
- Collection getChildrenNames() throws SourceException;
+ Source getChild(String name) throws SourceException;
/**
* Return the name of this source relative to its parent.
- * @throws SourceException if some problem occurs.
- */
- String getName() throws SourceException;
-
- /**
- * Return the absolute URI of the parent source.
- *
- * @return the parent URI, or <code>null</code> if this source has no parent.
- * @throws SourceException if some problem occurs.
+ *
+ * @return the name
*/
- String getParentURI() throws SourceException;
+ String getName();
/**
* Get the parent of this source as a [EMAIL PROTECTED] Source} object.
@@ -123,6 +113,5 @@
* @return the parent source, or <code>null</code> if this source has no parent.
* @throws SourceException if some problem occurs.
*/
- Source getParentSource() throws SourceException;
-
+ Source getParent() throws SourceException;
}
1.5 +392 -91
avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/impl/FileSource.java
Index: FileSource.java
===================================================================
RCS file:
/home/cvs/avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/impl/FileSource.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- FileSource.java 31 Mar 2003 14:21:42 -0000 1.4
+++ FileSource.java 4 Apr 2003 16:36:51 -0000 1.5
@@ -55,111 +55,195 @@
package org.apache.excalibur.source.impl;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
-import java.net.URL;
+import java.net.MalformedURLException;
+import java.net.URLConnection;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.ConcurrentModificationException;
-import java.util.Map;
import org.apache.excalibur.source.ModifiableSource;
+import org.apache.excalibur.source.ModifiableTraversableSource;
+import org.apache.excalibur.source.MoveableSource;
+import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceException;
+import org.apache.excalibur.source.SourceNotFoundException;
+import org.apache.excalibur.source.SourceUtil;
+import org.apache.excalibur.source.SourceValidity;
+import org.apache.excalibur.source.impl.validity.FileTimeStampValidity;
/**
- * A [EMAIL PROTECTED] ModifiableSource} for 'file:/' system IDs.
+ * A [EMAIL PROTECTED] ModifiableTraversableSource} for filesystem objects.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Sylvain Wallez</a>
* @version $Id$
*/
-public class FileSource
- extends URLSource
- implements ModifiableSource {
+public class FileSource implements ModifiableTraversableSource, MoveableSource
+{
+
+ /** The file */
+ private File m_file;
+
+ /** The scheme */
+ private String m_scheme;
+
+ /** The URI of this source */
+ private String m_uri;
/**
- * Initialize a new object from a <code>URL</code>.
- * @param parameters This is optional
+ * Builds a FileSource given an URI, which doesn't necessarily have to start
with "file:"
+ * @param uri
+ * @throws SourceException
+ * @throws MalformedURLException
*/
- public void init(URL url,
- Map parameters )
- throws IOException {
- super.init( url, parameters );
+ public FileSource(String uri) throws SourceException, MalformedURLException
+ {
+ int pos = SourceUtil.indexOfSchemeColon(uri);
+ if (pos == -1)
+ {
+ throw new MalformedURLException("Invalid URI : " + uri);
+ }
+
+ String scheme = uri.substring(0, pos);
+ String fileName = uri.substring(pos + 1);
+ init(scheme, new File(fileName));
+ }
+
+ /**
+ * Builds a FileSource, given an URI scheme and a File.
+ *
+ * @param scheme
+ * @param file
+ * @throws SourceException
+ */
+ public FileSource(String scheme, File file) throws SourceException
+ {
+ init(scheme, file);
+ }
+
+ private void init(String scheme, File file) throws SourceException
+ {
+ m_scheme = scheme;
- if ( null == getFile() ) {
- throw new IllegalArgumentException("Malformed url for a file source : "
+ url);
+ String uri;
+ try
+ {
+ uri = file.toURL().toExternalForm();
}
+ catch (MalformedURLException mue)
+ {
+ // Can this really happen ?
+ throw new SourceException("Failed to get URL for file " + file, mue);
+ }
+
+ if (!uri.startsWith(scheme))
+ {
+ // Scheme is not "file:"
+ uri = scheme + ':' + uri.substring(uri.indexOf(':') + 1);
+ }
+
+ m_uri = uri;
+
+ m_file = file;
}
/**
* Get the associated file
*/
- public File getFile() {
- return super.getFile();
+ public File getFile()
+ {
+ return m_file;
}
+
//----------------------------------------------------------------------------------
+ // Source interface methods
+
//----------------------------------------------------------------------------------
+
/**
- * A file outputStream that will rename the temp file to the destination file
upon close()
- * and discard the temp file upon cancel().
+ * @see org.apache.excalibur.source.Source#getContentLength()
*/
- private class FileSourceOutputStream extends FileOutputStream {
-
- private File m_tmpFile;
- private boolean m_isClosed = false;
- private FileSource m_source;
+ public long getContentLength()
+ {
+ return m_file.length();
+ }
- public FileSourceOutputStream(File tmpFile, FileSource source) throws
IOException {
- super(tmpFile);
- m_tmpFile = tmpFile;
- m_source = source;
+ /**
+ * @see org.apache.excalibur.source.Source#getInputStream()
+ */
+ public InputStream getInputStream() throws IOException, SourceNotFoundException
+ {
+ try
+ {
+ return new FileInputStream(m_file);
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ throw new SourceNotFoundException(m_uri + " doesn't exist.", fnfe);
}
+ }
- public void close() throws IOException {
- if (!m_isClosed) {
- super.close();
- try {
- // Delete destination file
- if (m_source.getFile().exists()) {
- m_source.getFile().delete();
- }
- // Rename temp file to destination file
- m_tmpFile.renameTo(m_source.getFile());
-
- } finally {
- // Ensure temp file is deleted, ie lock is released.
- // If there was a failure above, written data is lost.
- if (m_tmpFile.exists()) {
- m_tmpFile.delete();
- }
- m_isClosed = true;
- }
- }
+ /**
+ * @see org.apache.excalibur.source.Source#getLastModified()
+ */
+ public long getLastModified()
+ {
+ return m_file.lastModified();
+ }
- }
+ /**
+ * @see org.apache.excalibur.source.Source#getMimeType()
+ */
+ public String getMimeType()
+ {
+ return URLConnection.getFileNameMap().getContentTypeFor(m_file.getName());
+ }
- public boolean canCancel() {
- return !m_isClosed;
- }
+ /* (non-Javadoc)
+ * @see org.apache.excalibur.source.Source#getScheme()
+ */
+ public String getScheme()
+ {
+ return m_scheme;
- public void cancel() throws Exception {
- if (m_isClosed) {
- throw new IllegalStateException("Cannot cancel : outputstrem is
already closed");
- }
+ }
- m_isClosed = true;
- super.close();
- m_tmpFile.delete();
- }
+ /* (non-Javadoc)
+ * @see org.apache.excalibur.source.Source#getURI()
+ */
+ public String getURI()
+ {
+ return m_uri;
+ }
- public void finalize() {
- if (!m_isClosed && m_tmpFile.exists()) {
- // Something wrong happened while writing : delete temp file
- m_tmpFile.delete();
- }
+ /**
+ * Return a validity object based on the file's modification date.
+ *
+ * @see org.apache.excalibur.source.Source#getValidity()
+ */
+ public SourceValidity getValidity()
+ {
+ if (m_file.exists())
+ {
+ return new FileTimeStampValidity(m_file);
+ }
+ else
+ {
+ return null;
}
+ }
- public FileSource getSource() {
- return m_source;
- }
+ /**
+ * @see org.apache.excalibur.source.Source#refresh()
+ */
+ public void refresh()
+ {
+ // Nothing to do...
}
/**
@@ -167,26 +251,97 @@
*
* @return true if the resource exists.
*/
- public boolean exists() {
+ public boolean exists()
+ {
return getFile().exists();
}
+
//----------------------------------------------------------------------------------
+ // TraversableSource interface methods
+
//----------------------------------------------------------------------------------
+
+ /**
+ * @see org.apache.excalibur.source.TraversableSource#getChild(java.lang.String)
+ */
+ public Source getChild(String name) throws SourceException
+ {
+ if (!m_file.isDirectory())
+ {
+ throw new SourceException(getURI() + " is not a directory");
+ }
+
+ return new FileSource(this.getScheme(), new File(m_file, name));
+
+ }
+
+ /**
+ * @see org.apache.excalibur.source.TraversableSource#getChildren()
+ */
+ public Collection getChildren() throws SourceException
+ {
+
+ if (!m_file.isDirectory())
+ {
+ throw new SourceException(getURI() + " is not a directory");
+ }
+
+ // Build a FileSource object for each of the children
+ File[] files = m_file.listFiles();
+
+ FileSource[] children = new FileSource[files.length];
+ for (int i = 0; i < files.length; i++)
+ {
+ children[i] = new FileSource(this.getScheme(), files[i]);
+ }
+
+ // Return it as a list
+ return Arrays.asList(children);
+ }
+
+ /**
+ * @see org.apache.excalibur.source.TraversableSource#getName()
+ */
+ public String getName()
+ {
+ return m_file.getName();
+ }
+
+ /**
+ * @see org.apache.excalibur.source.TraversableSource#getParent()
+ */
+ public Source getParent() throws SourceException
+ {
+ return new FileSource(getScheme(), m_file.getParentFile());
+ }
+
+ /**
+ * @see org.apache.excalibur.source.TraversableSource#isCollection()
+ */
+ public boolean isCollection()
+ {
+ return m_file.isDirectory();
+ }
+
+
//----------------------------------------------------------------------------------
+ // ModifiableSource interface methods
+
//----------------------------------------------------------------------------------
+
/**
* Get an <code>InputStream</code> where raw bytes can be written to.
* The signification of these bytes is implementation-dependent and
* is not restricted to a serialized XML document.
*
- * Get an output stream to write to this source. The output stream returned
- * actually writes to a temp file that replaces the real one on close. This
- * temp file is used as lock to forbid multiple simultaneous writes. The
- * real file is updated atomically when the output stream is closed.
+ * The output stream returned actually writes to a temp file that replaces
+ * the real one on close. This temp file is used as lock to forbid multiple
+ * simultaneous writes. The real file is updated atomically when the output
+ * stream is closed.
*
* @return a stream to write to
* @throws ConcurrentModificationException if another thread is currently
* writing to this file.
*/
- public OutputStream getOutputStream()
- throws IOException, SourceException {
+ public OutputStream getOutputStream() throws IOException
+ {
// Create a temp file. It will replace the right one when writing
terminates,
// and serve as a lock to prevent concurrent writes.
File tmpFile = new File(getFile().getPath() + ".tmp");
@@ -195,14 +350,16 @@
tmpFile.getParentFile().mkdirs();
// Can we write the file ?
- if (getFile().exists() && !getFile().canWrite()) {
+ if (getFile().exists() && !getFile().canWrite())
+ {
throw new IOException("Cannot write to file " + getFile().getPath());
}
// Check if it temp file already exists, meaning someone else currently
writing
- if (!tmpFile.createNewFile()) {
- throw new ConcurrentModificationException("File " + getFile().getPath()
+
- " is already being written by another thread");
+ if (!tmpFile.createNewFile())
+ {
+ throw new ConcurrentModificationException(
+ "File " + getFile().getPath() + " is already being written by
another thread");
}
// Return a stream that will rename the temp file on close.
@@ -215,10 +372,13 @@
*
* @return true if the stream can be cancelled
*/
- public boolean canCancel(OutputStream stream) {
- if (stream instanceof FileSourceOutputStream) {
- FileSourceOutputStream fsos = (FileSourceOutputStream)stream;
- if (fsos.getSource() == this) {
+ public boolean canCancel(OutputStream stream)
+ {
+ if (stream instanceof FileSourceOutputStream)
+ {
+ FileSourceOutputStream fsos = (FileSourceOutputStream) stream;
+ if (fsos.getSource() == this)
+ {
return fsos.canCancel();
}
}
@@ -233,13 +393,19 @@
* <p>
* After cancel, the stream should no more be used.
*/
- public void cancel(OutputStream stream) throws SourceException {
- if (stream instanceof FileSourceOutputStream) {
- FileSourceOutputStream fsos = (FileSourceOutputStream)stream;
- if (fsos.getSource() == this) {
- try {
+ public void cancel(OutputStream stream) throws SourceException
+ {
+ if (stream instanceof FileSourceOutputStream)
+ {
+ FileSourceOutputStream fsos = (FileSourceOutputStream) stream;
+ if (fsos.getSource() == this)
+ {
+ try
+ {
fsos.cancel();
- } catch (Exception e) {
+ }
+ catch (Exception e)
+ {
throw new SourceException("Exception during cancel.", e);
}
return;
@@ -253,7 +419,142 @@
/**
* Delete the source.
*/
- public boolean delete() {
- return getFile().delete();
+ public boolean delete()
+ {
+ return m_file.delete();
+ }
+
+
//----------------------------------------------------------------------------------
+ // ModifiableTraversableSource interface methods
+
//----------------------------------------------------------------------------------
+
+ /**
+ * @see org.apache.excalibur.source.ModifiableTraversableSource#makeCollection()
+ */
+ public void makeCollection() throws SourceException
+ {
+ m_file.mkdirs();
+ }
+
+
//----------------------------------------------------------------------------------
+ // MoveableSource interface methods
+
//----------------------------------------------------------------------------------
+
+ /**
+ * @see
org.apache.excalibur.source.MoveableSource#copy(org.apache.excalibur.source.Source)
+ */
+ public void copyTo(Source destination) throws SourceException
+ {
+ try
+ {
+ SourceUtil.copy(this.getInputStream(), ((ModifiableSource)
destination).getOutputStream());
+ }
+ catch (IOException ioe)
+ {
+ throw new SourceException("Couldn't copy " + getURI() + " to " +
destination.getURI(), ioe);
+ }
+ }
+
+ /**
+ * @see
org.apache.excalibur.source.MoveableSource#move(org.apache.excalibur.source.Source)
+ */
+ public void moveTo(Source destination) throws SourceException
+ {
+ if (destination instanceof FileSource)
+ {
+ if (!m_file.renameTo(((FileSource) destination).getFile()))
+ {
+ throw new SourceException("Couldn't move " + getURI() + " to " +
destination.getURI());
+ }
+ }
+ else
+ {
+ SourceUtil.move(this, destination);
+ }
+
+ }
+
+
//----------------------------------------------------------------------------------
+ // Private helper class for ModifiableSource implementation
+
//----------------------------------------------------------------------------------
+
+ /**
+ * A file outputStream that will rename the temp file to the destination file
upon close()
+ * and discard the temp file upon cancel().
+ */
+ private static class FileSourceOutputStream extends FileOutputStream
+ {
+
+ private File m_tmpFile;
+ private boolean m_isClosed = false;
+ private FileSource m_source;
+
+ public FileSourceOutputStream(File tmpFile, FileSource source) throws
IOException
+ {
+ super(tmpFile);
+ m_tmpFile = tmpFile;
+ m_source = source;
+ }
+
+ public void close() throws IOException
+ {
+ if (!m_isClosed)
+ {
+ super.close();
+ try
+ {
+ // Delete destination file
+ if (m_source.getFile().exists())
+ {
+ m_source.getFile().delete();
+ }
+ // Rename temp file to destination file
+ m_tmpFile.renameTo(m_source.getFile());
+
+ }
+ finally
+ {
+ // Ensure temp file is deleted, ie lock is released.
+ // If there was a failure above, written data is lost.
+ if (m_tmpFile.exists())
+ {
+ m_tmpFile.delete();
+ }
+ m_isClosed = true;
+ }
+ }
+
+ }
+
+ public boolean canCancel()
+ {
+ return !m_isClosed;
+ }
+
+ public void cancel() throws Exception
+ {
+ if (m_isClosed)
+ {
+ throw new IllegalStateException("Cannot cancel : outputstrem is
already closed");
+ }
+
+ m_isClosed = true;
+ super.close();
+ m_tmpFile.delete();
+ }
+
+ public void finalize()
+ {
+ if (!m_isClosed && m_tmpFile.exists())
+ {
+ // Something wrong happened while writing : delete temp file
+ m_tmpFile.delete();
+ }
+ }
+
+ public FileSource getSource()
+ {
+ return m_source;
+ }
}
}
1.10 +11 -4
avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/impl/ResourceSource.java
Index: ResourceSource.java
===================================================================
RCS file:
/home/cvs/avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/impl/ResourceSource.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- ResourceSource.java 29 Mar 2003 18:53:26 -0000 1.9
+++ ResourceSource.java 4 Apr 2003 16:36:51 -0000 1.10
@@ -56,12 +56,14 @@
import java.io.IOException;
import java.io.InputStream;
+import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceException;
import org.apache.excalibur.source.SourceNotFoundException;
+import org.apache.excalibur.source.SourceUtil;
import org.apache.excalibur.source.SourceValidity;
import org.apache.excalibur.source.impl.validity.NOPValidity;
@@ -80,10 +82,15 @@
private URL m_location;
private String m_mimeType;
- public ResourceSource( final String systemId )
+ public ResourceSource( final String systemId ) throws MalformedURLException
{
+ final int pos = SourceUtil.indexOfSchemeColon(systemId);
+ if (pos == -1 || ! systemId.startsWith("://", pos))
+ {
+ throw new MalformedURLException("Invalid format for ResourceSource : "
+ systemId);
+ }
+
setSystemId(systemId);
- final int pos = systemId.indexOf( "://" );
m_location = getClassLoader().getResource(systemId.substring( pos + 3 ));
setScheme(systemId.substring(0, pos));
}
@@ -141,7 +148,7 @@
return NOPValidity.SHARED_INSTANCE;
}
- private ClassLoader getClassLoader() {
+ protected ClassLoader getClassLoader() {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
if( loader == null )
{
1.30 +4 -3
avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/impl/SourceResolverImpl.java
Index: SourceResolverImpl.java
===================================================================
RCS file:
/home/cvs/avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/impl/SourceResolverImpl.java,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -r1.29 -r1.30
--- SourceResolverImpl.java 4 Feb 2003 20:12:59 -0000 1.29
+++ SourceResolverImpl.java 4 Apr 2003 16:36:51 -0000 1.30
@@ -75,6 +75,7 @@
import org.apache.excalibur.source.SourceException;
import org.apache.excalibur.source.SourceFactory;
import org.apache.excalibur.source.SourceResolver;
+import org.apache.excalibur.source.SourceUtil;
/**
* This is the default implemenation of a [EMAIL PROTECTED] SourceResolver}.
@@ -203,7 +204,7 @@
getLogger().debug( "Resolving '" + location + "' with base '" + baseURI
+ "' in context '" + m_baseURL + "'" );
}
if( location == null ) throw new MalformedURLException( "Invalid System ID"
);
- if( null != baseURI && baseURI.indexOf( ':' ) == -1 )
+ if( null != baseURI && SourceUtil.indexOfSchemeColon(baseURI) == -1 )
{
throw new MalformedURLException( "BaseURI is not valid, it must contain
a protocol: " + baseURI );
}
@@ -270,7 +271,7 @@
Source source = null;
// search for a SourceFactory implementing the protocol
- final int protocolPos = systemID.indexOf( ':' );
+ final int protocolPos = SourceUtil.indexOfSchemeColon(systemID);
if( protocolPos != -1)
{
final String protocol = systemID.substring( 0, protocolPos );
1.24 +108 -207
avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/impl/URLSource.java
Index: URLSource.java
===================================================================
RCS file:
/home/cvs/avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/impl/URLSource.java,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -r1.23 -r1.24
--- URLSource.java 31 Mar 2003 14:21:42 -0000 1.23
+++ URLSource.java 4 Apr 2003 16:36:51 -0000 1.24
@@ -54,29 +54,21 @@
*/
package org.apache.excalibur.source.impl;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceException;
-import org.apache.excalibur.source.SourceNotFoundException;
import org.apache.excalibur.source.SourceParameters;
import org.apache.excalibur.source.SourceResolver;
import org.apache.excalibur.source.SourceUtil;
import org.apache.excalibur.source.SourceValidity;
-import org.apache.excalibur.source.impl.validity.FileTimeStampValidity;
import org.apache.excalibur.source.impl.validity.TimeStampValidity;
/**
@@ -85,12 +77,8 @@
* @author <a href="mailto:[EMAIL PROTECTED]">Carsten Ziegeler</a>
* @version CVS $Revision$ $Date$
*/
-public class URLSource
- extends AbstractSource
- implements Source
+public class URLSource extends AbstractSource implements Source
{
- /** Identifier for file urls */
- protected final String FILE = "file:";
/** The URL of the source */
protected URL m_url;
@@ -98,21 +86,15 @@
/** The connection for a real URL */
protected URLConnection m_connection;
- /** The file, if URL is a file
- * @deprecated use the accessor instead (getFile())
- */
- protected File file;
-
/** The <code>SourceParameters</code> used for a post*/
protected SourceParameters m_parameters;
/** Is this a post? */
protected boolean m_isPost = false;
-
+
/** Does this source exist ? */
protected boolean m_exists = false;
-
/** the prev returned SourceValidity */
protected SourceValidity m_cachedValidity;
@@ -120,7 +102,7 @@
/** The content type (if known) */
protected String m_mimeType;
-
+
/**
* Constructor
*/
@@ -132,78 +114,56 @@
* Initialize a new object from a <code>URL</code>.
* @param parameters This is optional
*/
- public void init( URL url,
- Map parameters )
- throws IOException
+ public void init(URL url, Map parameters) throws IOException
{
String systemId = url.toExternalForm();
setSystemId(systemId);
- int pos = systemId.indexOf(':');
- setScheme(systemId.substring(0, pos));
- if (systemId.startsWith( FILE ))
- {
- setFile( new File( systemId.substring( FILE.length() ) ) );
- }
- else
- {
- setFile( null );
- }
+ setScheme(SourceUtil.getScheme(systemId));
+
m_url = url;
m_isPost = false;
-
- if( null != parameters )
+
+ if (null != parameters)
{
- m_parameters = (SourceParameters)parameters.get(
SourceResolver.URI_PARAMETERS );
- final String method = (String)parameters.get( SourceResolver.METHOD );
- if( "POST".equalsIgnoreCase( method ) )
+ m_parameters = (SourceParameters)
parameters.get(SourceResolver.URI_PARAMETERS);
+ final String method = (String) parameters.get(SourceResolver.METHOD);
+
+ if ("POST".equalsIgnoreCase(method))
m_isPost = true;
}
- if( null == getFile()
- && null != m_parameters
- && m_parameters.hasParameters()
- && !m_isPost )
+
+ if (null != m_parameters && m_parameters.hasParameters() && !m_isPost)
{
- StringBuffer urlBuffer = new StringBuffer( systemId );
+ StringBuffer urlBuffer = new StringBuffer(systemId);
String key;
final Iterator i = m_parameters.getParameterNames();
Iterator values;
String value;
- boolean first = ( systemId.indexOf( '?' ) == -1 );
- if( first == true ) urlBuffer.append( '?' );
- while( i.hasNext() )
+ boolean first = (systemId.indexOf('?') == -1);
+ if (first == true)
+ urlBuffer.append('?');
+ while (i.hasNext())
{
- key = (String)i.next();
- values = m_parameters.getParameterValues( key );
- while( values.hasNext() == true )
+ key = (String) i.next();
+ values = m_parameters.getParameterValues(key);
+ while (values.hasNext() == true)
{
- value = SourceUtil.encode( (String)values.next() );
- if( first == false ) urlBuffer.append( '&' );
+ value = SourceUtil.encode((String) values.next());
+ if (first == false)
+ urlBuffer.append('&');
first = false;
- urlBuffer.append( key );
- urlBuffer.append( '=' );
- urlBuffer.append( value );
+ urlBuffer.append(key);
+ urlBuffer.append('=');
+ urlBuffer.append(value);
}
}
-
- m_url = new URL( urlBuffer.toString() );
+
+ m_url = new URL(urlBuffer.toString());
m_parameters = null;
}
}
/**
- * @param file
- */
- protected void setFile(File file)
- {
- this.file = file;
- }
-
- protected File getFile()
- {
- return file;
- }
-
- /**
* Get the last modification date and content length of the source.
* Any exceptions are ignored.
* Override this to get the real information
@@ -212,44 +172,35 @@
{
// exists will be set below depending on the m_url type
m_exists = false;
-
- if( null != getFile() )
- {
- setLastModified( getFile().lastModified() );
- setContentLength( getFile().length() );
- m_exists = getFile().exists();
- }
- else
+
+ if (!m_isPost)
{
- if( !m_isPost )
+ try
{
- try
+ if (null == m_connection)
{
- if( null == m_connection )
+ m_connection = m_url.openConnection();
+ String userInfo = getUserInfo();
+ if (m_url.getProtocol().startsWith("http") && userInfo != null)
{
- m_connection = m_url.openConnection();
- String userInfo = getUserInfo();
- if( m_url.getProtocol().startsWith( "http" ) && userInfo !=
null )
- {
- m_connection.setRequestProperty( "Authorization",
"Basic " + SourceUtil.encodeBASE64( userInfo ) );
- }
+ m_connection.setRequestProperty("Authorization", "Basic " +
SourceUtil.encodeBASE64(userInfo));
}
- setLastModified(m_connection.getLastModified());
- setContentLength(m_connection.getContentLength());
- m_mimeType = m_connection.getContentType();
- m_exists = true;
- }
- catch( IOException ignore )
- {
- super.getInfos();
}
+ setLastModified(m_connection.getLastModified());
+ setContentLength(m_connection.getContentLength());
+ m_mimeType = m_connection.getContentType();
+ m_exists = true;
}
- else
+ catch (IOException ignore)
{
- // do not open m_connection when using post!
super.getInfos();
}
}
+ else
+ {
+ // do not open m_connection when using post!
+ super.getInfos();
+ }
}
/**
@@ -268,89 +219,74 @@
* HTTP location does not exist.
* @throws IOException if I/O error occured.
*/
- public InputStream getInputStream()
- throws IOException, SourceException
+ public InputStream getInputStream() throws IOException, SourceException
{
- try
+ checkInfos();
+ InputStream input = null;
+ if (m_connection == null)
{
- checkInfos();
- InputStream input = null;
- if( null != getFile() )
+ m_connection = m_url.openConnection();
+ /* The following requires a jdk 1.3 */
+ String userInfo = getUserInfo();
+ if (m_url.getProtocol().startsWith("http") && userInfo != null)
{
- input = new FileInputStream( getFile() );
+ m_connection.setRequestProperty("Authorization", "Basic " +
SourceUtil.encodeBASE64(userInfo));
}
- else
+
+ // do a post operation
+ if (m_connection instanceof HttpURLConnection && m_isPost)
{
- if( m_connection == null )
+ StringBuffer buffer = new StringBuffer(2000);
+ String key;
+ Iterator i = m_parameters.getParameterNames();
+ Iterator values;
+ String value;
+ boolean first = true;
+ while (i.hasNext())
{
- m_connection = m_url.openConnection();
- /* The following requires a jdk 1.3 */
- String userInfo = getUserInfo();
- if( m_url.getProtocol().startsWith( "http" ) && userInfo !=
null )
+ key = (String) i.next();
+ values = m_parameters.getParameterValues(key);
+ while (values.hasNext() == true)
{
- m_connection.setRequestProperty( "Authorization", "Basic "
+ SourceUtil.encodeBASE64( userInfo ) );
+ value = SourceUtil.encode((String) values.next());
+ if (first == false)
+ buffer.append('&');
+ first = false;
+ buffer.append(key.toString());
+ buffer.append('=');
+ buffer.append(value);
}
+ }
+ HttpURLConnection httpCon = (HttpURLConnection) m_connection;
+ httpCon.setDoInput(true);
- // do a post operation
- if( m_connection instanceof HttpURLConnection
- && m_isPost )
- {
- StringBuffer buffer = new StringBuffer( 2000 );
- String key;
- Iterator i = m_parameters.getParameterNames();
- Iterator values;
- String value;
- boolean first = true;
- while( i.hasNext() )
- {
- key = (String)i.next();
- values = m_parameters.getParameterValues( key );
- while( values.hasNext() == true )
- {
- value = SourceUtil.encode( (String)values.next() );
- if( first == false ) buffer.append( '&' );
- first = false;
- buffer.append( key.toString() );
- buffer.append( '=' );
- buffer.append( value );
- }
- }
- HttpURLConnection httpCon = (HttpURLConnection)m_connection;
- httpCon.setDoInput( true );
-
- if( buffer.length() > 1 )
- { // only post if we have parameters
- String postString = buffer.toString();
- httpCon.setRequestMethod( "POST" ); // this is POST
- httpCon.setDoOutput( true );
- httpCon.setRequestProperty( "Content-type",
"application/x-www-form-urlencoded" );
-
- // A content-length header must be contained in a POST
request
- httpCon.setRequestProperty( "Content-length",
Integer.toString( postString.length() ) );
- java.io.OutputStream out = new
java.io.BufferedOutputStream( httpCon.getOutputStream() );
- out.write( postString.getBytes() );
- out.close();
- }
- input = httpCon.getInputStream();
- m_connection = null; // make sure a new m_connection is
created next time
- return input;
- }
+ if (buffer.length() > 1)
+ { // only post if we have parameters
+ String postString = buffer.toString();
+ httpCon.setRequestMethod("POST"); // this is POST
+ httpCon.setDoOutput(true);
+ httpCon.setRequestProperty("Content-type",
"application/x-www-form-urlencoded");
+
+ // A content-length header must be contained in a POST request
+ httpCon.setRequestProperty("Content-length",
Integer.toString(postString.length()));
+ java.io.OutputStream out = new
java.io.BufferedOutputStream(httpCon.getOutputStream());
+ out.write(postString.getBytes());
+ out.close();
}
- input = m_connection.getInputStream();
+ input = httpCon.getInputStream();
m_connection = null; // make sure a new m_connection is created
next time
+ return input;
}
- return input;
- }
- catch (FileNotFoundException fnfe)
- {
- throw new SourceNotFoundException("Resource not found " + getURI());
}
+ input = m_connection.getInputStream();
+ m_connection = null; // make sure a new m_connection is created next time
+ return input;
}
private static boolean checkedURLClass = false;
private static boolean urlSupportsGetUserInfo = false;
private static Method urlGetUserInfo = null;
- private static Object[] emptyParams = new Object[ 0 ];
+ private static Object[] emptyParams = new Object[0];
/**
* Check if the <code>URL</code> class supports the getUserInfo()
@@ -358,15 +294,15 @@
*/
protected String getUserInfo()
{
- if( URLSource.checkedURLClass == true )
+ if (URLSource.checkedURLClass == true)
{
- if( URLSource.urlSupportsGetUserInfo == true )
+ if (URLSource.urlSupportsGetUserInfo == true)
{
try
{
- return (String)URLSource.urlGetUserInfo.invoke( m_url,
URLSource.emptyParams );
+ return (String) URLSource.urlGetUserInfo.invoke(m_url,
URLSource.emptyParams);
}
- catch( Exception e )
+ catch (Exception e)
{
// ignore this anyway
}
@@ -378,13 +314,13 @@
// test if the m_url class supports the getUserInfo method
try
{
- URLSource.urlGetUserInfo = URL.class.getMethod( "getUserInfo", null
);
- String ui = (String)URLSource.urlGetUserInfo.invoke( m_url,
URLSource.emptyParams );
+ URLSource.urlGetUserInfo = URL.class.getMethod("getUserInfo", null);
+ String ui = (String) URLSource.urlGetUserInfo.invoke(m_url,
URLSource.emptyParams);
URLSource.checkedURLClass = true;
URLSource.urlSupportsGetUserInfo = true;
return ui;
}
- catch( Exception e )
+ catch (Exception e)
{
}
URLSource.checkedURLClass = true;
@@ -403,20 +339,13 @@
public SourceValidity getValidity()
{
final long lm = getLastModified();
- if( lm > 0 )
+ if (lm > 0)
{
if (lm == m_cachedLastModificationDate)
return m_cachedValidity;
m_cachedLastModificationDate = lm;
- if (getFile() != null)
- {
- m_cachedValidity = new FileTimeStampValidity(getFile(), lm);
- }
- else
- {
- m_cachedValidity = new TimeStampValidity( lm );
- }
+ m_cachedValidity = new TimeStampValidity(lm);
return m_cachedValidity;
}
return null;
@@ -434,33 +363,6 @@
}
/**
- * Does this source point to a directory?
- */
- public boolean isDirectory()
- {
- if ( null != getFile() )
- {
- return getFile().isDirectory();
- }
- return false;
- }
-
- /**
- * Return the URIs of the children
- * The returned URIs are relative to the URI of the parent
- * (this object)
- */
- public Collection getChildrenLocations()
- {
- if ( null != getFile() && getFile().isDirectory() )
- {
- final String[] files = getFile().list();
- return Arrays.asList(files);
- }
- return Collections.EMPTY_LIST;
- }
-
- /**
* 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 null.
@@ -469,5 +371,4 @@
{
return m_mimeType;
}
-
}
1.4 +39 -92
avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/impl/URLSourceFactory.java
Index: URLSourceFactory.java
===================================================================
RCS file:
/home/cvs/avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/impl/URLSourceFactory.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- URLSourceFactory.java 7 Feb 2003 11:21:09 -0000 1.3
+++ URLSourceFactory.java 4 Apr 2003 16:36:52 -0000 1.4
@@ -54,144 +54,91 @@
*/
package org.apache.excalibur.source.impl;
-import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
-import org.apache.avalon.framework.parameters.ParameterException;
-import org.apache.avalon.framework.parameters.Parameterizable;
-import org.apache.avalon.framework.parameters.Parameters;
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;
/**
* A factory for a [EMAIL PROTECTED] URL} wrapper
*
* @author <a href="mailto:[EMAIL PROTECTED]">Carsten Ziegeler</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Sylvain Wallez</a>
* @version $Id$
*/
-public class URLSourceFactory
- extends AbstractLogEnabled
- implements SourceFactory, Parameterizable, ThreadSafe
+public class URLSourceFactory extends AbstractLogEnabled implements SourceFactory,
ThreadSafe
{
- /** The URLSource class used */
- protected Class m_urlSourceClass;
-
- public void parameterize( Parameters pars )
- throws ParameterException
+ /**
+ * Create an URL-based source. This class actually creates an [EMAIL PROTECTED]
URLSource}, but if another
+ * implementation is needed, subclasses can override this method.
+ */
+ protected Source createURLSource(URL url, Map parameters) throws
MalformedURLException, IOException
{
- final String urlSourceClassName = pars.getParameter( "url-source",
-
"org.apache.excalibur.source.impl.URLSource" );
- ClassLoader loader = Thread.currentThread().getContextClassLoader();
- if( loader == null )
- {
- loader = getClass().getClassLoader();
- }
- try
- {
- m_urlSourceClass = loader.loadClass( urlSourceClassName );
- }
- catch( ClassNotFoundException cnfe )
- {
- this.getLogger().error( "Class not found: " + urlSourceClassName, cnfe
);
- throw new ParameterException( "Class not found: " + urlSourceClassName,
cnfe );
- }
+ URLSource result = new URLSource();
+ result.init(url, parameters);
+ return result;
}
/**
- * Create a correct instance for the uri
+ * Create an file-based source. This class actually creates an [EMAIL
PROTECTED] FileSource}, but if another
+ * implementation is needed, subclasses can override this method.
*/
- protected URLSource getSourceImplementation(String uri, Map parameters)
- throws Exception
+ protected Source createFileSource(String uri) throws MalformedURLException,
IOException
{
- if (uri.startsWith("file:"))
- {
- final URLSource fileSource = (URLSource)new FileSource();
- fileSource.init( new URL( uri ), parameters);
- return fileSource;
- }
- else
- {
- final URLSource urlSource =
- (URLSource)this.m_urlSourceClass.newInstance();
- urlSource.init( new URL( uri ), parameters );
- return urlSource;
- }
+ return new FileSource(uri);
}
-
+
/**
* @see org.apache.excalibur.source.SourceFactory#getSource(java.lang.String,
java.util.Map)
*/
- public Source getSource(String uri, Map parameters)
- throws MalformedURLException, IOException
+ public Source getSource(String uri, Map parameters) throws
MalformedURLException, IOException
{
- if( getLogger().isDebugEnabled() )
+ if (getLogger().isDebugEnabled())
{
final String message = "Creating source object for " + uri;
- getLogger().debug( message );
+ getLogger().debug(message);
}
- Source source;
- try
+ // First check if it's a file
+ if (uri.startsWith("file:"))
{
- if( getLogger().isDebugEnabled() == true )
- {
- this.getLogger().debug( "Making URL from " + uri );
- }
- try
- {
- source = this.getSourceImplementation( uri, parameters );
- }
- catch( MalformedURLException mue )
- {
- throw mue;
- }
- catch( Exception ie )
- {
- throw new SourceException( "Unable to create new instance of " +
- this.m_urlSourceClass, ie );
- }
+ // Yes : return a file source
+ return createFileSource(uri);
}
- catch( MalformedURLException mue )
+ else
{
- if( getLogger().isDebugEnabled() )
- {
- this.getLogger().debug( "Making URL - MalformedURLException in
getURL:", mue );
- this.getLogger().debug( "Making URL a File (assuming that it is
full path):" + uri );
- }
+ // Not a "file:" : create an URLSource
+ // First try to create the URL
+ URL url;
try
{
- final URLSource urlSource = new FileSource();
- urlSource.init( ( new File( uri ) ).toURL(), parameters );
- source = urlSource;
+ url = new URL(uri);
}
- catch( Exception ie )
+ catch (MalformedURLException mue)
{
- throw new SourceException( "Unable to create new instance of " +
- this.m_urlSourceClass, ie );
+ // Maybe a file name containing a ':' ?
+ if (getLogger().isDebugEnabled())
+ {
+ this.getLogger().debug("URL " + uri + " is malformed. Assuming
it's a file path.", mue);
+ }
+ return createFileSource(uri);
}
- }
- return source;
+ return createURLSource(url, parameters);
+ }
}
/**
* @see
org.apache.excalibur.source.SourceFactory#release(org.apache.excalibur.source.Source)
*/
- public void release(Source source) {
- if( null != source && getLogger().isDebugEnabled() )
- {
- final String message = "Releasing source object for " + source.getURI();
- getLogger().debug( message );
- }
+ public void release(Source source)
+ {
// do nothing here
}
-
}
-
1.1
avalon-excalibur/sourceresolve/src/java/org/apache/excalibur/source/impl/FileSourceFactory.java
Index: FileSourceFactory.java
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002 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 "Jakarta", "Avalon", 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.excalibur.source.impl;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Map;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceFactory;
/**
* A factory for filesystem-based sources (see [EMAIL PROTECTED] FileSource}).
*
* @author <a href="mailto:[EMAIL PROTECTED]">Sylvain Wallez</a>
* @version $Id: FileSourceFactory.java,v 1.1 2003/04/04 16:36:51 sylvain Exp $
*/
public class FileSourceFactory implements SourceFactory, ThreadSafe
{
/**
* @see org.apache.excalibur.source.SourceFactory#getSource(java.lang.String,
java.util.Map)
*/
public Source getSource(String location, Map parameters) throws IOException,
MalformedURLException
{
return new FileSource(location);
}
/**
* Does nothing, since [EMAIL PROTECTED] FileSource}s don't need to be released.
*
* @see
org.apache.excalibur.source.SourceFactory#release(org.apache.excalibur.source.Source)
*/
public void release(Source source)
{
// Nothing to do here
}
}
1.1
avalon-excalibur/sourceresolve/src/test/org/apache/excalibur/source/test/FileSourceTestCase.java
Index: FileSourceTestCase.java
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002 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 "Jakarta", "Avalon", 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.excalibur.source.test;
import java.io.File;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import junit.framework.TestCase;
import org.apache.excalibur.source.ModifiableSource;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceUtil;
import org.apache.excalibur.source.SourceValidity;
import org.apache.excalibur.source.impl.FileSource;
/**
* Test case for FileSource.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Sylvain Wallez</a>
* @version $Id: FileSourceTestCase.java,v 1.1 2003/04/04 16:36:52 sylvain Exp $
*/
public class FileSourceTestCase extends TestCase
{
private File m_tempDir;
public FileSourceTestCase()
{
this("FileSource");
}
public FileSourceTestCase(String name)
{
super(name);
}
protected void setUp() throws Exception
{
// Create a temp file
m_tempDir = File.createTempFile("filesource", "test");
// and make it a directory
m_tempDir.delete();
m_tempDir.mkdir();
}
public void testDirExistence() throws Exception
{
FileSource src = new FileSource("file", m_tempDir);
assertTrue("Temp dir doesn't exist", src.exists());
assertTrue("Temp dir is not traversable", src.isCollection());
// Check it was created less than 1 secs ago
assertEquals("Wrong creation date", System.currentTimeMillis() / 1000L,
src.getLastModified() / 1000L);
assertTrue("Temp dir is not empty", src.getChildren().isEmpty());
}
public void testChildCreation() throws Exception
{
final String text = "Writing to a source";
FileSource src = new FileSource("file", m_tempDir);
FileSource child = (FileSource) src.getChild("child.txt");
assertTrue("New file already exists", !child.exists());
// Should not have a validity, since it doesn't exist
assertNull("New file has a validity", child.getValidity());
// Test the name
assertEquals("Wrong name", "child.txt", child.getName());
// Feed with some content
fillSource(child, text);
// And test it
assertEquals(
"Wrong length",
text.length() + System.getProperty("line.separator").length(),
child.getContentLength());
assertEquals("Wrong content-type", "text/plain", child.getMimeType());
assertTrue("New file is traversable", !child.isCollection());
// Check that parent now has children
Collection children = src.getChildren();
assertEquals("Wrong number of children", 1, children.size());
// And also that crawling up the hierarchy is OK
Source parent = child.getParent();
assertEquals("Wrong parent URI", src.getURI(), parent.getURI());
}
public void testMove() throws Exception
{
final String text = "Original text";
FileSource src = new FileSource("file", m_tempDir);
FileSource child = (FileSource) src.getChild("child.txt");
assertTrue("New file already exists", !child.exists());
fillSource(child, text);
assertTrue("New file doesn't exist", child.exists());
long length = child.getContentLength();
FileSource child2 = (FileSource) src.getChild("child2.txt");
assertTrue("Second file already exist", !child2.exists());
SourceUtil.move(child, child2);
assertTrue("First file still exists", !child.exists());
assertTrue("Second file doesn't exist", child2.exists());
assertEquals("Wrong length of second file", length,
child2.getContentLength());
}
public void testCopy() throws Exception
{
final String text = "Original text";
FileSource src = new FileSource("file", m_tempDir);
FileSource child = (FileSource) src.getChild("child.txt");
assertTrue("New file already exists", !child.exists());
fillSource(child, text);
assertTrue("New file doesn't exist", child.exists());
long length = child.getContentLength();
FileSource child2 = (FileSource) src.getChild("child2.txt");
assertTrue("Second file already exist", !child2.exists());
SourceUtil.copy(child, child2);
assertTrue("First file doesn't exist", child.exists());
assertTrue("Second file doesn't exist", child2.exists());
assertEquals("Wrong length of second file", length,
child2.getContentLength());
}
public void testDelete() throws Exception
{
final String text = "Original text";
FileSource src = new FileSource("file", m_tempDir);
FileSource child = (FileSource) src.getChild("child.txt");
assertTrue("New file already exists", !child.exists());
fillSource(child, text);
assertTrue("New file doesn't exist", child.exists());
child.delete();
assertTrue("File still exists", !child.exists());
}
public void testConcurrentAccess() throws Exception
{
FileSource src = new FileSource("file", m_tempDir);
FileSource child = (FileSource) src.getChild("child.txt");
assertTrue("New file already exists", !child.exists());
OutputStream os = child.getOutputStream();
try
{
// Get it a second time
OutputStream os2 = child.getOutputStream();
}
catch (ConcurrentModificationException cme)
{
return; // This is what is expected
}
fail("Undedected concurrent modification");
}
public void testAtomicUpdate() throws Exception
{
final String text = "Blah, blah";
FileSource src = new FileSource("file", m_tempDir);
FileSource child = (FileSource) src.getChild("child.txt");
assertTrue("New file already exists", !child.exists());
fillSource(child, text + " and blah!");
long length = child.getContentLength();
SourceValidity validity = child.getValidity();
assertEquals("Validity is not valid", 1, validity.isValid());
// Wait a bit, otherwise the update speed is faster than the clock
resolution
Thread.sleep(100L);
// Now change its content
PrintWriter pw = new PrintWriter(child.getOutputStream());
pw.write(text);
assertEquals("File length modified", length, child.getContentLength());
pw.close();
assertTrue("File length not modified", length != child.getContentLength());
assertEquals("Validity is valid", -1, validity.isValid());
}
protected void tearDown() throws Exception
{
deleteAll(m_tempDir);
}
// Recursively delete a file or directory
private void deleteAll(File f)
{
if (f.isDirectory())
{
File[] children = f.listFiles();
for (int i = 0; i < children.length; i++)
{
deleteAll(children[i]);
}
}
f.delete();
}
private void fillSource(ModifiableSource src, String text) throws Exception
{
OutputStream os = src.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.println("Writing to a source");
pw.close();
}
}
1.1
avalon-excalibur/sourceresolve/src/test/org/apache/excalibur/source/test/SourceResolverImplTestCase.java
Index: SourceResolverImplTestCase.java
===================================================================
package org.apache.excalibur.source.test;
import java.io.File;
import junit.framework.TestCase;
import org.apache.avalon.framework.context.DefaultContext;
import org.apache.avalon.framework.logger.ConsoleLogger;
import org.apache.avalon.framework.logger.Logger;
import org.apache.avalon.framework.service.DefaultServiceManager;
import org.apache.avalon.framework.service.DefaultServiceSelector;
import org.apache.excalibur.source.SourceFactory;
import org.apache.excalibur.source.impl.ResourceSourceFactory;
import org.apache.excalibur.source.impl.SourceResolverImpl;
public class SourceResolverImplTestCase extends TestCase
{
public SourceResolverImplTestCase( )
{
this( "source" );
}
public SourceResolverImplTestCase( String name )
{
super( name );
}
public void testResolver() throws Exception
{
Logger logger = new ConsoleLogger( ConsoleLogger.LEVEL_DEBUG );
//
// create the component to handle source resolution
//
final SourceResolverImpl resolver = new SourceResolverImpl();
resolver.enableLogging( logger );
//
// create the context argument and set the root directory and
// contextualize the resolver
//
// NOTE: javadoc needed on contextualize method
//
final DefaultContext context = new DefaultContext();
context.put( "context-root", new File( System.getProperty( "user.dir" ) ) );
resolver.contextualize( context );
//
// create a service selector to be included in a service manager
// to be supplied to the resolver
//
final ResourceSourceFactory factory = new ResourceSourceFactory();
factory.enableLogging( logger.getChildLogger( "factory" ) );
// create a selector and add the factory to the selector,
// add the selector to the manager, and service the resolver
// NOTE: javadoc missing on the serviceable method
//
final DefaultServiceSelector selector = new DefaultServiceSelector();
selector.put( "resource", factory );
final DefaultServiceManager manager = new DefaultServiceManager();
manager.put( SourceFactory.ROLE + "Selector", selector );
resolver.service( manager );
logger.debug( "resolver created - but is this correct ?" );
//
// setup a protocol handler - TO BE DONE
//
logger.debug( "help me - need to setup a handler" );
//
// test source URL creation - TO BE DONE
//
logger.debug( "help me - need to test source creation" );
//
// test source resolution - TO BE DONE
//
logger.debug( "help me - need to test source resolution" );
assertTrue( true );
}
}
1.1
avalon-excalibur/sourceresolve/src/test/org/apache/excalibur/source/test/SourceUtilTestCase.java
Index: SourceUtilTestCase.java
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002 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 "Jakarta", "Avalon", 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.excalibur.source.test;
import org.apache.excalibur.source.SourceUtil;
import junit.framework.TestCase;
/**
* Test case for SourceUtil.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Sylvain Wallez</a>
* @version $Id: SourceUtilTestCase.java,v 1.1 2003/04/04 16:36:52 sylvain Exp $
*/
public class SourceUtilTestCase extends TestCase
{
public SourceUtilTestCase()
{
this("SourceUtil");
}
public SourceUtilTestCase(String name)
{
super(name);
}
public void testNominalScheme() throws Exception
{
String uri = "http://foo";
assertEquals(4, SourceUtil.indexOfSchemeColon(uri));
assertEquals("http", SourceUtil.getScheme(uri));
assertEquals("//foo", SourceUtil.getSpecificPart(uri));
}
public void testDoubleColon() throws Exception
{
assertEquals(4, SourceUtil.indexOfSchemeColon("file:foo:bar"));
}
public void testSpecialScheme() throws Exception
{
String uri = "a-+.:foo"; // Strange, but valid !
assertEquals(4, SourceUtil.indexOfSchemeColon(uri));
assertEquals("a-+.", SourceUtil.getScheme(uri));
assertEquals("foo", SourceUtil.getSpecificPart(uri));
}
public void testSpecialPart() throws Exception
{
String uri = "bar:";
assertEquals(3, SourceUtil.indexOfSchemeColon(uri));
assertEquals("bar", SourceUtil.getScheme(uri));
assertEquals("", SourceUtil.getSpecificPart(uri));
}
public void testInvalidScheme() throws Exception
{
String uri = "2foo:bar";
assertEquals(-1, SourceUtil.indexOfSchemeColon(uri));
assertEquals(null, SourceUtil.getScheme(uri));
assertEquals(null, SourceUtil.getSpecificPart(uri));
// Invalid character before any of the allowed ones
assertEquals(-1, SourceUtil.indexOfSchemeColon("h ttp:foo"));
assertEquals(-1, SourceUtil.indexOfSchemeColon(" http:foo"));
assertEquals(-1, SourceUtil.indexOfSchemeColon("http :foo"));
// Invalid character between allowed ranges
assertEquals(-1, SourceUtil.indexOfSchemeColon("h_ttp:foo"));
assertEquals(-1, SourceUtil.indexOfSchemeColon("_http:foo"));
assertEquals(-1, SourceUtil.indexOfSchemeColon("http_:foo"));
// Invalid character after any of the allowed ones
assertEquals(-1, SourceUtil.indexOfSchemeColon("h~ttp:foo"));
assertEquals(-1, SourceUtil.indexOfSchemeColon("~http:foo"));
assertEquals(-1, SourceUtil.indexOfSchemeColon("http~:foo"));
assertEquals(-1, SourceUtil.indexOfSchemeColon("/file/with:colon"));
assertEquals(-1, SourceUtil.indexOfSchemeColon(".foo:bar"));
assertEquals(-1, SourceUtil.indexOfSchemeColon("no-colon"));
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]