You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuscany.apache.org by ad...@apache.org on 2008/04/16 10:52:27 UTC

svn commit: r648628 [2/2] - in /incubator/tuscany/sandbox/mobile-android: contribution-impl/ contribution-impl/src/ contribution-impl/src/main/ contribution-impl/src/main/java/ contribution-impl/src/main/java/org/ contribution-impl/src/main/java/org/ap...

Added: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/util/FileHelper.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/util/FileHelper.java?rev=648628&view=auto
==============================================================================
--- incubator/tuscany/sandbox/mobile-android/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/util/FileHelper.java (added)
+++ incubator/tuscany/sandbox/mobile-android/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/util/FileHelper.java Wed Apr 16 01:52:20 2008
@@ -0,0 +1,701 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.tuscany.sca.contribution.service.util;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.regex.Pattern;
+
+public class FileHelper {
+    /**
+     * The extension separator character.
+     */
+    private static final char EXTENSION_SEPARATOR = '.';
+
+    /**
+     * The Unix separator character.
+     */
+    private static final char UNIX_SEPARATOR = '/';
+
+    /**
+     * The Windows separator character.
+     */
+    private static final char WINDOWS_SEPARATOR = '\\';
+
+    /**
+     * Returns the index of the last directory separator character.
+     * <p>
+     * This method will handle a file in either Unix or Windows format. The
+     * position of the last forward or backslash is returned.
+     * <p>
+     * The output will be the same irrespective of the machine that the code is
+     * running on.
+     * 
+     * @param filename the filename to find the last path separator in, null
+     *            returns -1
+     * @return the index of the last separator character, or -1 if there is no
+     *         such character
+     */
+    public static int indexOfLastSeparator(String filename) {
+        if (filename == null) {
+            return -1;
+        }
+        int lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR);
+        int lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR);
+        return Math.max(lastUnixPos, lastWindowsPos);
+    }
+
+    /**
+     * Returns the index of the last extension separator character, which is a
+     * dot.
+     * <p>
+     * This method also checks that there is no directory separator after the
+     * last dot. To do this it uses {@link #indexOfLastSeparator(String)} which
+     * will handle a file in either Unix or Windows format.
+     * <p>
+     * The output will be the same irrespective of the machine that the code is
+     * running on.
+     * 
+     * @param filename the filename to find the last path separator in, null
+     *            returns -1
+     * @return the index of the last separator character, or -1 if there is no
+     *         such character
+     */
+    public static int indexOfExtension(String filename) {
+        if (filename == null) {
+            return -1;
+        }
+        int extensionPos = filename.lastIndexOf(EXTENSION_SEPARATOR);
+        int lastSeparator = indexOfLastSeparator(filename);
+        return lastSeparator > extensionPos ? -1 : extensionPos;
+    }
+
+    /**
+     * Gets the name minus the path from a full filename.
+     * <p>
+     * This method will handle a file in either Unix or Windows format. The text
+     * after the last forward or backslash is returned.
+     * 
+     * <pre>
+     * a/b/c.txt --&gt; c.txt
+     * a.txt     --&gt; a.txt
+     * a/b/c     --&gt; c
+     * a/b/c/    --&gt; &quot;&quot;
+     * </pre>
+     * 
+     * <p>
+     * The output will be the same irrespective of the machine that the code is
+     * running on.
+     * 
+     * @param fileName the filename to query, null returns null
+     * @return the name of the file without the path, or an empty string if none
+     *         exists
+     */
+    public static String getName(String fileName) {
+        if (fileName == null) {
+            return null;
+        }
+        int index = indexOfLastSeparator(fileName);
+        return fileName.substring(index + 1);
+    }
+
+    /**
+     * Gets the extension of a filename.
+     * <p>
+     * This method returns the textual part of the filename after the last dot.
+     * There must be no directory separator after the dot.
+     * 
+     * <pre>
+     * foo.txt      --&gt; &quot;txt&quot;
+     * a/b/c.jpg    --&gt; &quot;jpg&quot;
+     * a/b.txt/c    --&gt; &quot;&quot;
+     * a/b/c        --&gt; &quot;&quot;
+     * </pre>
+     * 
+     * <p>
+     * The output will be the same irrespective of the machine that the code is
+     * running on.
+     * 
+     * @param filename the filename to retrieve the extension of.
+     * @return the extension of the file or an empty string if none exists.
+     */
+    public static String getExtension(String filename) {
+        if (filename == null) {
+            return null;
+        }
+        int index = indexOfExtension(filename);
+        if (index == -1) {
+            return "";
+        } else {
+            return filename.substring(index + 1);
+        }
+    }
+
+    /**
+     * Make a directory, including any necessary but nonexistent parent
+     * directories. If there already exists a file with specified name or the
+     * directory cannot be created then an exception is thrown.
+     * 
+     * @param directory directory to create, not null
+     * @throws NullPointerException if the directory is null
+     * @throws IOException if the directory cannot be created
+     */
+    public static void forceMkdir(File directory) throws IOException {
+        if (directory.exists()) {
+            if (directory.isFile()) {
+                String message =
+                    "File " + directory + " exists and is " + "not a directory. Unable to create directory.";
+                throw new IOException(message);
+            }
+        } else {
+            if (!directory.mkdirs()) {
+                String message = "Unable to create directory " + directory;
+                throw new IOException(message);
+            }
+        }
+    }
+
+    /**
+     * Delete a file. If file is a directory, delete it and all sub-directories.
+     * <p>
+     * The difference between File.delete() and this method are:
+     * <ul>
+     * <li>A directory to be deleted does not have to be empty.</li>
+     * <li>You get exceptions when a file or directory cannot be deleted.
+     * (java.io.File methods returns a boolean)</li>
+     * </ul>
+     * 
+     * @param file file or directory to delete, not null
+     * @throws NullPointerException if the directory is null
+     * @throws IOException in case deletion is unsuccessful
+     */
+    public static void forceDelete(File file) throws IOException {
+        if (file.isDirectory()) {
+            deleteDirectory(file);
+        } else {
+            if (!file.exists()) {
+                throw new FileNotFoundException("File does not exist: " + file);
+            }
+            if (!file.delete()) {
+                String message = "Unable to delete file: " + file;
+                throw new IOException(message);
+            }
+        }
+    }
+
+    /**
+     * Convert from a <code>URL</code> to a <code>File</code>.
+     * <p>
+     * From version 1.1 this method will decode the URL. Syntax such as
+     * <code>file:///my%20docs/file.txt</code> will be correctly decoded to
+     * <code>/my docs/file.txt</code>.
+     * 
+     * @param url the file URL to convert, null returns null
+     * @return the equivalent <code>File</code> object, or <code>null</code>
+     *         if the URL's protocol is not <code>file</code>
+     * @throws IllegalArgumentException if the file is incorrectly encoded
+     */
+    public static File toFile(URL url) {
+        if (url == null || !url.getProtocol().equals("file")) {
+            return null;
+        } else {
+            String filename = url.getFile().replace('/', File.separatorChar);
+            int pos = 0;
+            while ((pos = filename.indexOf('%', pos)) >= 0) { // NOPMD
+                if (pos + 2 < filename.length()) {
+                    String hexStr = filename.substring(pos + 1, pos + 3);
+                    char ch = (char)Integer.parseInt(hexStr, 16);
+                    filename = filename.substring(0, pos) + ch + filename.substring(pos + 3);
+                }
+            }
+            return new File(filename);
+        }
+    }
+
+    public static FileFilter getFileFilter(String regExp, boolean ignoreCase) {
+        return new RegExpFilter(regExp, ignoreCase);
+    }
+
+    /**
+     * A regular-expression based resource filter
+     */
+    public static class RegExpFilter implements FileFilter {
+        private Pattern pattern;
+
+        public RegExpFilter(Pattern pattern) {
+            this.pattern = pattern;
+        }
+
+        public RegExpFilter(String patternStr, boolean ignoreCase) {
+            this.pattern = Pattern.compile(patternStr, ignoreCase ? Pattern.CASE_INSENSITIVE : 0);
+        }
+
+        public boolean accept(File file) {
+            return pattern.matcher(file.getName()).matches();
+        }
+
+        /**
+         * Convert wildcard into a regex pattern
+         * 
+         * @param str
+         * @return
+         */
+        public static RegExpFilter getWildcardFilter(String str, boolean ignoreCase) {
+            StringBuffer buffer = new StringBuffer();
+            for (int i = 0; i < str.length(); i++) {
+                char ch = str.charAt(i);
+                if (ch == '?') {
+                    buffer.append('.');
+                } else if (ch == '*') {
+                    buffer.append(".*");
+                } else {
+                    buffer.append(ch);
+                }
+            }
+            return new RegExpFilter(buffer.toString(), ignoreCase);
+        }
+
+    }
+
+    /**
+     * Clean a directory without deleting it.
+     * 
+     * @param directory directory to clean
+     * @throws IOException in case cleaning is unsuccessful
+     */
+    public static void cleanDirectory(File directory) throws IOException {
+        if (!directory.exists()) {
+            String message = directory + " does not exist";
+            throw new IllegalArgumentException(message);
+        }
+
+        if (!directory.isDirectory()) {
+            String message = directory + " is not a directory";
+            throw new IllegalArgumentException(message);
+        }
+
+        File[] files = directory.listFiles();
+        if (files == null) { // null if security restricted
+            throw new IOException("Failed to list contents of " + directory);
+        }
+
+        IOException exception = null;
+        for (int i = 0; i < files.length; i++) {
+            File file = files[i];
+            try {
+                forceDelete(file);
+            } catch (IOException ioe) {
+                exception = ioe;
+            }
+        }
+
+        if (null != exception) {
+            throw exception;
+        }
+    }
+
+    /**
+     * Clean a directory without deleting it.
+     * 
+     * @param directory directory to clean, must not be <code>null</code>
+     * @throws NullPointerException if the directory is <code>null</code>
+     * @throws IOException in case cleaning is unsuccessful
+     */
+    private static void cleanDirectoryOnExit(File directory) throws IOException {
+        if (!directory.exists()) {
+            String message = directory + " does not exist";
+            throw new IllegalArgumentException(message);
+        }
+
+        if (!directory.isDirectory()) {
+            String message = directory + " is not a directory";
+            throw new IllegalArgumentException(message);
+        }
+
+        File[] files = directory.listFiles();
+        if (files == null) { // null if security restricted
+            throw new IOException("Failed to list contents of " + directory);
+        }
+
+        IOException exception = null;
+        for (int i = 0; i < files.length; i++) {
+            File file = files[i];
+            try {
+                forceDeleteOnExit(file);
+            } catch (IOException ioe) {
+                exception = ioe;
+            }
+        }
+
+        if (null != exception) {
+            throw exception;
+        }
+    }
+
+    /**
+     * Copies a whole directory to a new location preserving the file dates.
+     * <p>
+     * This method copies the specified directory and all its child directories
+     * and files to the specified destination. The destination is the new
+     * location and name of the directory.
+     * <p>
+     * The destination directory is created if it does not exist. If the
+     * destination directory did exist, then this method merges the source with
+     * the destination, with the source taking precedence.
+     * 
+     * @param srcDir an existing directory to copy, must not be
+     *            <code>null</code>
+     * @param destDir the new directory, must not be <code>null</code>
+     * @throws NullPointerException if source or destination is
+     *             <code>null</code>
+     * @throws IOException if source or destination is invalid
+     * @throws IOException if an IO error occurs during copying
+     * @since Commons IO 1.1
+     */
+    public static void copyDirectory(File srcDir, File destDir) throws IOException {
+        copyDirectory(srcDir, destDir, true);
+    }
+
+    /**
+     * Copies a whole directory to a new location.
+     * <p>
+     * This method copies the contents of the specified source directory to
+     * within the specified destination directory.
+     * <p>
+     * The destination directory is created if it does not exist. If the
+     * destination directory did exist, then this method merges the source with
+     * the destination, with the source taking precedence.
+     * 
+     * @param srcDir an existing directory to copy, must not be
+     *            <code>null</code>
+     * @param destDir the new directory, must not be <code>null</code>
+     * @param preserveFileDate true if the file date of the copy should be the
+     *            same as the original
+     * @throws NullPointerException if source or destination is
+     *             <code>null</code>
+     * @throws IOException if source or destination is invalid
+     * @throws IOException if an IO error occurs during copying
+     * @since Commons IO 1.1
+     */
+    public static void copyDirectory(File srcDir, File destDir, boolean preserveFileDate) throws IOException {
+        if (srcDir == null) {
+            throw new NullPointerException("Source must not be null");
+        }
+        if (destDir == null) {
+            throw new NullPointerException("Destination must not be null");
+        }
+        if (!srcDir.exists()) {
+            throw new FileNotFoundException("Source '" + srcDir + "' does not exist");
+        }
+        if (!srcDir.isDirectory()) {
+            throw new IOException("Source '" + srcDir + "' exists but is not a directory");
+        }
+        if (srcDir.getCanonicalPath().equals(destDir.getCanonicalPath())) {
+            throw new IOException("Source '" + srcDir + "' and destination '" + destDir + "' are the same");
+        }
+        doCopyDirectory(srcDir, destDir, preserveFileDate);
+    }
+
+    // -----------------------------------------------------------------------
+    /**
+     * Copies a directory to within another directory preserving the file dates.
+     * <p>
+     * This method copies the source directory and all its contents to a
+     * directory of the same name in the specified destination directory.
+     * <p>
+     * The destination directory is created if it does not exist. If the
+     * destination directory did exist, then this method merges the source with
+     * the destination, with the source taking precedence.
+     * 
+     * @param srcDir an existing directory to copy, must not be
+     *            <code>null</code>
+     * @param destDir the directory to place the copy in, must not be
+     *            <code>null</code>
+     * @throws NullPointerException if source or destination is
+     *             <code>null</code>
+     * @throws IOException if source or destination is invalid
+     * @throws IOException if an IO error occurs during copying
+     * @since Commons IO 1.2
+     */
+    public static void copyDirectoryToDirectory(File srcDir, File destDir) throws IOException {
+        if (srcDir == null) {
+            throw new NullPointerException("Source must not be null");
+        }
+        if (!(srcDir.exists() && srcDir.isDirectory())) {
+            throw new IllegalArgumentException("Source '" + destDir + "' is not a directory");
+        }
+        if (destDir == null) {
+            throw new NullPointerException("Destination must not be null");
+        }
+        if (!(destDir.exists() && destDir.isDirectory())) {
+            throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory");
+        }
+        copyDirectory(srcDir, new File(destDir, srcDir.getName()), true);
+    }
+
+    /**
+     * Copies a file to a new location preserving the file date.
+     * <p>
+     * This method copies the contents of the specified source file to the
+     * specified destination file. The directory holding the destination file is
+     * created if it does not exist. If the destination file exists, then this
+     * method will overwrite it.
+     * 
+     * @param srcFile an existing file to copy, must not be <code>null</code>
+     * @param destFile the new file, must not be <code>null</code>
+     * @throws NullPointerException if source or destination is
+     *             <code>null</code>
+     * @throws IOException if source or destination is invalid
+     * @throws IOException if an IO error occurs during copying
+     * @see #copyFileToDirectory(File, File)
+     */
+    public static void copyFile(File srcFile, File destFile) throws IOException {
+        copyFile(srcFile, destFile, true);
+    }
+
+    /**
+     * Copies a file to a new location.
+     * <p>
+     * This method copies the contents of the specified source file to the
+     * specified destination file. The directory holding the destination file is
+     * created if it does not exist. If the destination file exists, then this
+     * method will overwrite it.
+     * 
+     * @param srcFile an existing file to copy, must not be <code>null</code>
+     * @param destFile the new file, must not be <code>null</code>
+     * @param preserveFileDate true if the file date of the copy should be the
+     *            same as the original
+     * @throws NullPointerException if source or destination is
+     *             <code>null</code>
+     * @throws IOException if source or destination is invalid
+     * @throws IOException if an IO error occurs during copying
+     * @see #copyFileToDirectory(File, File, boolean)
+     */
+    public static void copyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException {
+        if (srcFile == null) {
+            throw new NullPointerException("Source must not be null");
+        }
+        if (destFile == null) {
+            throw new NullPointerException("Destination must not be null");
+        }
+        if (!srcFile.exists()) {
+            throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
+        }
+        if (srcFile.isDirectory()) {
+            throw new IOException("Source '" + srcFile + "' exists but is a directory");
+        }
+        if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) {
+            throw new IOException("Source '" + srcFile + "' and destination '" + destFile + "' are the same");
+        }
+        if (!(destFile.getParentFile() != null && destFile.getParentFile().exists())) {
+            if (!destFile.getParentFile().mkdirs()) { //NOPMD
+                throw new IOException("Destination '" + destFile + "' directory cannot be created");
+            }
+        }
+        if (!(destFile.exists() && destFile.canWrite())) {
+            throw new IOException("Destination '" + destFile + "' exists but is read-only");
+        }
+        doCopyFile(srcFile, destFile, preserveFileDate);
+    }
+
+    // -----------------------------------------------------------------------
+    /**
+     * Copies a file to a directory preserving the file date.
+     * <p>
+     * This method copies the contents of the specified source file to a file of
+     * the same name in the specified destination directory. The destination
+     * directory is created if it does not exist. If the destination file
+     * exists, then this method will overwrite it.
+     * 
+     * @param srcFile an existing file to copy, must not be <code>null</code>
+     * @param destDir the directory to place the copy in, must not be
+     *            <code>null</code>
+     * @throws NullPointerException if source or destination is null
+     * @throws IOException if source or destination is invalid
+     * @throws IOException if an IO error occurs during copying
+     * @see #copyFile(File, File, boolean)
+     */
+    public static void copyFileToDirectory(File srcFile, File destDir) throws IOException {
+        copyFileToDirectory(srcFile, destDir, true);
+    }
+
+    /**
+     * Copies a file to a directory optionally preserving the file date.
+     * <p>
+     * This method copies the contents of the specified source file to a file of
+     * the same name in the specified destination directory. The destination
+     * directory is created if it does not exist. If the destination file
+     * exists, then this method will overwrite it.
+     * 
+     * @param srcFile an existing file to copy, must not be <code>null</code>
+     * @param destDir the directory to place the copy in, must not be
+     *            <code>null</code>
+     * @param preserveFileDate true if the file date of the copy should be the
+     *            same as the original
+     * @throws NullPointerException if source or destination is
+     *             <code>null</code>
+     * @throws IOException if source or destination is invalid
+     * @throws IOException if an IO error occurs during copying
+     * @see #copyFile(File, File, boolean)
+     * @since Commons IO 1.3
+     */
+    public static void copyFileToDirectory(File srcFile, File destDir, boolean preserveFileDate) throws IOException {
+        if (destDir == null) {
+            throw new NullPointerException("Destination must not be null");
+        }
+        if (!(destDir.exists() && destDir.isDirectory())) {
+            throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory");
+        }
+        copyFile(srcFile, new File(destDir, srcFile.getName()), preserveFileDate);
+    }
+
+    // -----------------------------------------------------------------------
+    /**
+     * Recursively delete a directory.
+     * 
+     * @param directory directory to delete
+     * @throws IOException in case deletion is unsuccessful
+     */
+    public static void deleteDirectory(File directory) throws IOException {
+        if (!directory.exists()) {
+            return;
+        }
+
+        cleanDirectory(directory);
+        if (!directory.delete()) {
+            String message = "Unable to delete directory " + directory + ".";
+            throw new IOException(message);
+        }
+    }
+
+    /**
+     * Recursively schedule directory for deletion on JVM exit.
+     * 
+     * @param directory directory to delete, must not be <code>null</code>
+     * @throws NullPointerException if the directory is <code>null</code>
+     * @throws IOException in case deletion is unsuccessful
+     */
+    private static void deleteDirectoryOnExit(File directory) throws IOException {
+        if (!directory.exists()) {
+            return;
+        }
+
+        cleanDirectoryOnExit(directory);
+        directory.deleteOnExit();
+    }
+
+    /**
+     * Internal copy directory method.
+     * 
+     * @param srcDir the validated source directory, must not be
+     *            <code>null</code>
+     * @param destDir the validated destination directory, must not be
+     *            <code>null</code>
+     * @param preserveFileDate whether to preserve the file date
+     * @throws IOException if an error occurs
+     * @since Commons IO 1.1
+     */
+    private static void doCopyDirectory(File srcDir, File destDir, boolean preserveFileDate) throws IOException {
+        if (destDir.exists()) {
+            if (!destDir.isDirectory()) {
+                throw new IOException("Destination '" + destDir + "' exists but is not a directory");
+            }
+        } else {
+            if (!destDir.mkdirs()) {
+                throw new IOException("Destination '" + destDir + "' directory cannot be created");
+            }
+            if (preserveFileDate) {
+                destDir.setLastModified(srcDir.lastModified());
+            }
+        }
+        if (!destDir.canWrite()) {
+            throw new IOException("Destination '" + destDir + "' cannot be written to");
+        }
+        // recurse
+        File[] files = srcDir.listFiles();
+        if (files == null) { // null if security restricted
+            throw new IOException("Failed to list contents of " + srcDir);
+        }
+        for (int i = 0; i < files.length; i++) {
+            File copiedFile = new File(destDir, files[i].getName());
+            if (files[i].isDirectory()) {
+                doCopyDirectory(files[i], copiedFile, preserveFileDate);
+            } else {
+                doCopyFile(files[i], copiedFile, preserveFileDate);
+            }
+        }
+    }
+
+    /**
+     * Internal copy file method.
+     * 
+     * @param srcFile the validated source file, must not be <code>null</code>
+     * @param destFile the validated destination file, must not be
+     *            <code>null</code>
+     * @param preserveFileDate whether to preserve the file date
+     * @throws IOException if an error occurs
+     */
+    private static void doCopyFile(File srcFile, File destFile, boolean preserveFileDate) throws IOException {
+        if (destFile.exists() && destFile.isDirectory()) {
+            throw new IOException("Destination '" + destFile + "' exists but is a directory");
+        }
+
+        FileInputStream input = new FileInputStream(srcFile);
+        try {
+            FileOutputStream output = new FileOutputStream(destFile);
+            try {
+                IOHelper.copy(input, output);
+            } finally {
+                IOHelper.closeQuietly(output);
+            }
+        } finally {
+            IOHelper.closeQuietly(input);
+        }
+
+        if (srcFile.length() != destFile.length()) {
+            throw new IOException("Failed to copy full contents from '" + srcFile + "' to '" + destFile + "'");
+        }
+        if (preserveFileDate) {
+            destFile.setLastModified(srcFile.lastModified());
+        }
+    }
+
+    /**
+     * Schedule a file to be deleted when JVM exits. If file is directory delete
+     * it and all sub-directories.
+     * 
+     * @param file file or directory to delete, must not be <code>null</code>
+     * @throws NullPointerException if the file is <code>null</code>
+     * @throws IOException in case deletion is unsuccessful
+     */
+    public static void forceDeleteOnExit(File file) throws IOException {
+        if (file.isDirectory()) {
+            deleteDirectoryOnExit(file);
+        } else {
+            file.deleteOnExit();
+        }
+    }
+
+}

Added: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/util/IOHelper.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/util/IOHelper.java?rev=648628&view=auto
==============================================================================
--- incubator/tuscany/sandbox/mobile-android/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/util/IOHelper.java (added)
+++ incubator/tuscany/sandbox/mobile-android/contribution-impl/src/main/java/org/apache/tuscany/sca/contribution/service/util/IOHelper.java Wed Apr 16 01:52:20 2008
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.tuscany.sca.contribution.service.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.jar.JarFile;
+
+public class IOHelper {
+    /**
+     * The default buffer size to use.
+     */
+    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+    
+    /**
+     * Unconditionally close an <code>InputStream</code>.
+     * <p>
+     * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
+     * This is typically used in finally blocks.
+     *
+     * @param input  the InputStream to close, may be null or already closed
+     */
+    public static void closeQuietly(InputStream input) {
+        try {
+            if (input != null) {
+                input.close();
+            }
+        } catch (IOException ioe) {
+            // ignore
+        }
+    }
+    
+    /**
+     * Unconditionally close an <code>OutputStream</code>.
+     * <p>
+     * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored.
+     * This is typically used in finally blocks.
+     *
+     * @param output  the OutputStream to close, may be null or already closed
+     */
+    public static void closeQuietly(OutputStream output) {
+        try {
+            if (output != null) {
+                output.close();
+            }
+        } catch (IOException ioe) {
+            // ignore
+        }
+    }
+    
+    /**
+     * Copy bytes from an <code>InputStream</code> to an
+     * <code>OutputStream</code>.
+     * <p>
+     * This method buffers the input internally, so there is no need to use a
+     * <code>BufferedInputStream</code>.
+     *
+     * @param input  the <code>InputStream</code> to read from
+     * @param output  the <code>OutputStream</code> to write to
+     * @return the number of bytes copied
+     * @throws NullPointerException if the input or output is null
+     * @throws IOException if an I/O error occurs
+     * @since Commons IO 1.1
+     */
+    public static int copy(InputStream input, OutputStream output) throws IOException {
+        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+        int count = 0;
+        int n = 0;
+        while (-1 != (n = input.read(buffer))) { // NOPMD
+            output.write(buffer, 0, n);
+            count += n;
+        }
+        return count;
+    }
+    
+    public static InputStream getInputStream(URL url) throws IOException {
+        return new SafeURLInputStream(url);
+    }
+    
+    /**
+     * This class is a workaround for URL stream issue as illustrated below.
+     * InputStream is=url.getInputStream(); is.close(); // This line doesn't close
+     * the JAR file if the URL is a jar entry like "jar:file:/a.jar!/my.composite" We
+     * also need to turn off the JarFile cache.
+     * 
+     * @see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4950148
+     * 
+     * @version $Rev: 641216 $ $Date: 2008-03-26 01:15:08 -0800 (Wed, 26 Mar 2008) $
+     */
+    public static class SafeURLInputStream extends InputStream {
+        private JarFile jarFile;
+        private InputStream is;
+
+        public SafeURLInputStream(URL url) throws IOException {
+            String protocol = url.getProtocol();
+            if (protocol != null && (protocol.equals("jar"))) {
+                JarURLConnection connection = (JarURLConnection)url.openConnection();
+                // We cannot use cache
+                connection.setUseCaches(false);
+                try {
+                    is = connection.getInputStream();
+                } catch (IOException e) {
+                    throw e;
+                }
+                jarFile = connection.getJarFile();
+            } else {
+                URLConnection connection = url.openConnection();
+                connection.setUseCaches(false);
+                is = connection.getInputStream();
+            }
+        }
+
+        public SafeURLInputStream(JarURLConnection connection) throws IOException {
+            // We cannot use cache
+            connection.setUseCaches(false);
+            is = connection.getInputStream();
+            jarFile = connection.getJarFile();
+        }
+
+        @Override
+        public int available() throws IOException {
+            return is.available();
+        }
+
+        @Override
+        public void close() throws IOException {
+            is.close();
+            // We need to close the JAR file
+            if (jarFile != null) {
+                jarFile.close();
+            }
+        }
+
+        @Override
+        public synchronized void mark(int readlimit) {
+            is.mark(readlimit);
+        }
+
+        @Override
+        public boolean markSupported() {
+            return is.markSupported();
+        }
+
+        @Override
+        public int read() throws IOException {
+            return is.read();
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            return is.read(b, off, len);
+        }
+
+        @Override
+        public int read(byte[] b) throws IOException {
+            return is.read(b);
+        }
+
+        @Override
+        public synchronized void reset() throws IOException {
+            is.reset();
+        }
+
+        @Override
+        public long skip(long n) throws IOException {
+            return is.skip(n);
+        }
+    }   
+}
\ No newline at end of file

Added: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.PackageProcessor
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/contribution-impl/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.PackageProcessor?rev=648628&view=auto
==============================================================================
--- incubator/tuscany/sandbox/mobile-android/contribution-impl/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.PackageProcessor (added)
+++ incubator/tuscany/sandbox/mobile-android/contribution-impl/src/main/resources/META-INF/services/org.apache.tuscany.sca.contribution.processor.PackageProcessor Wed Apr 16 01:52:20 2008
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License. 
+
+org.apache.tuscany.sca.contribution.processor.impl.FolderContributionProcessor;type=application/vnd.tuscany.folder
+org.apache.tuscany.sca.contribution.processor.impl.JarContributionProcessor;type=application/x-compressed

Added: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/processor/FolderContributionPackageProcessorTestCase.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/processor/FolderContributionPackageProcessorTestCase.java?rev=648628&view=auto
==============================================================================
--- incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/processor/FolderContributionPackageProcessorTestCase.java (added)
+++ incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/processor/FolderContributionPackageProcessorTestCase.java Wed Apr 16 01:52:20 2008
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.tuscany.sca.contribution.processor;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URL;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.tuscany.sca.contribution.processor.impl.FolderContributionProcessor;
+
+/**
+ * Folder Package Processor test case
+ * Verifies proper handle of File System structured contributions
+ * 
+ * @version $Rev: 618718 $ $Date: 2008-02-05 09:45:08 -0800 (Tue, 05 Feb 2008) $
+ */
+public class FolderContributionPackageProcessorTestCase extends TestCase {
+    private static final String FOLDER_CONTRIBUTION = ".";
+    
+    public final void testProcessPackageArtifacts() throws Exception {
+        FolderContributionProcessor folderProcessor = new FolderContributionProcessor();
+        URL contributionURL = new File(FOLDER_CONTRIBUTION).toURL().toURI().toURL();
+
+        List<URI> artifacts = folderProcessor.getArtifacts(contributionURL, null);
+        assertNotNull(artifacts);
+    }
+}

Added: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/processor/JarContributionPackageProcessorTestCase.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/processor/JarContributionPackageProcessorTestCase.java?rev=648628&view=auto
==============================================================================
--- incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/processor/JarContributionPackageProcessorTestCase.java (added)
+++ incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/processor/JarContributionPackageProcessorTestCase.java Wed Apr 16 01:52:20 2008
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.tuscany.sca.contribution.processor;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URL;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.tuscany.sca.contribution.processor.impl.JarContributionProcessor;
+import org.apache.tuscany.sca.contribution.service.util.IOHelper;
+
+/**
+ * JAR Package Processor test case
+ * Verifies proper handle of JAR Archives contributions
+ * 
+ * @version $Rev: 618158 $ $Date: 2008-02-03 18:44:47 -0800 (Sun, 03 Feb 2008) $
+ */
+
+public class JarContributionPackageProcessorTestCase extends TestCase {
+    private static final String JAR_CONTRIBUTION = "/repository/sample-calculator.jar";
+    
+    public final void testProcessPackageArtifacts() throws Exception {
+        JarContributionProcessor jarProcessor = new JarContributionProcessor();
+
+        URL jarURL = getClass().getResource(JAR_CONTRIBUTION);
+        InputStream jarStream = jarURL.openStream();
+        List<URI> artifacts = null;
+        try {
+            artifacts = jarProcessor.getArtifacts(jarURL, jarStream);
+        } finally {
+            IOHelper.closeQuietly(jarStream);
+        }
+        
+        assertNotNull(artifacts);
+    }
+}

Added: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/processor/URLartifactProcessorExtensionPointTestCase.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/processor/URLartifactProcessorExtensionPointTestCase.java?rev=648628&view=auto
==============================================================================
--- incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/processor/URLartifactProcessorExtensionPointTestCase.java (added)
+++ incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/processor/URLartifactProcessorExtensionPointTestCase.java Wed Apr 16 01:52:20 2008
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.tuscany.sca.contribution.processor;
+
+import java.net.URI;
+import java.net.URL;
+
+import junit.framework.TestCase;
+
+import org.apache.tuscany.sca.contribution.resolver.ModelResolver;
+import org.apache.tuscany.sca.contribution.service.ContributionReadException;
+import org.apache.tuscany.sca.contribution.service.ContributionResolveException;
+
+
+/**
+ * URL Artifact Processor Extension Point test case
+ * Verifies the right registration and lookup for processors that handle filename and file types
+ * 
+ * @version $Rev: 618158 $ $Date: 2008-02-03 18:44:47 -0800 (Sun, 03 Feb 2008) $
+ */
+public class URLartifactProcessorExtensionPointTestCase extends TestCase {
+    
+    private URLArtifactProcessorExtensionPoint artifactProcessors;
+    
+    @Override
+    protected void setUp() throws Exception {
+        artifactProcessors = new DefaultURLArtifactProcessorExtensionPoint(null);
+        artifactProcessors.addArtifactProcessor(new FileTypeArtifactProcessor());
+        artifactProcessors.addArtifactProcessor(new FileNameArtifactProcessor());
+    }
+    
+    
+    public final void testFileTypeProcessor() {
+        assertNotNull(artifactProcessors.getProcessor(".m1"));
+    }
+    
+    
+    public final void testFileNameProcessor() {
+        assertNotNull(artifactProcessors.getProcessor("file.m2"));
+        
+    }
+    
+    /**
+     * Internal mock classes
+     *
+     */
+    
+    private class M1 {
+    }
+    
+    private class M2 {
+    }
+    
+    private class FileTypeArtifactProcessor implements URLArtifactProcessor<M1> {
+        public FileTypeArtifactProcessor() {
+        }
+
+        public M1 read(URL contributionURL, URI uri, URL url) throws ContributionReadException {
+            return null;
+        }
+        
+        public void resolve(M1 m1, ModelResolver resolver) throws ContributionResolveException {
+        }
+
+        public String getArtifactType() {
+            return ".m1";
+        }
+        
+        public Class<M1> getModelType() {
+            return M1.class;
+        }        
+    }
+    
+    private class FileNameArtifactProcessor implements URLArtifactProcessor<M2> {
+        public FileNameArtifactProcessor() {
+        }
+
+        public M2 read(URL contributionURL, URI uri, URL url) throws ContributionReadException {
+            return null;
+        }
+        
+        public void resolve(M2 m2, ModelResolver resolver) throws ContributionResolveException {
+        }
+
+        public String getArtifactType() {
+            return "file.m2";
+        }
+        
+        public Class<M2> getModelType() {
+            return M2.class;
+        }        
+    }
+
+}

Added: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/resolver/DefaultModelResolverTestCase.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/resolver/DefaultModelResolverTestCase.java?rev=648628&view=auto
==============================================================================
--- incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/resolver/DefaultModelResolverTestCase.java (added)
+++ incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/resolver/DefaultModelResolverTestCase.java Wed Apr 16 01:52:20 2008
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.tuscany.sca.contribution.resolver;
+
+import junit.framework.TestCase;
+
+import org.apache.tuscany.sca.contribution.Artifact;
+import org.apache.tuscany.sca.contribution.ContributionFactory;
+import org.apache.tuscany.sca.contribution.DefaultContributionFactory;
+
+/**
+ * Test the default model resolver implementation.
+ *
+ * @version $Rev: 631808 $ $Date: 2008-02-27 17:49:26 -0800 (Wed, 27 Feb 2008) $
+ */
+public class DefaultModelResolverTestCase extends TestCase {
+    
+    private ModelResolver resolver;
+    private ContributionFactory factory;
+    
+    @Override
+    protected void setUp() throws Exception {
+        resolver = new DefaultModelResolver();
+        factory = new DefaultContributionFactory();
+    }
+    
+    public void testResolved() {
+        Model a = new Model("a");
+        resolver.addModel(a);
+        Model x = new Model("a");
+        x = resolver.resolveModel(Model.class, x);
+        assertTrue(x == a);
+    }
+    
+    public void testUnresolved() {
+        Model x = new Model("a");
+        Model y = resolver.resolveModel(Model.class, x);
+        assertTrue(x == y);
+    }
+        
+    public void testResolvedArtifact() {
+        Artifact artifact = factory.createArtifact();
+        artifact.setURI("foo/bar");
+        resolver.addModel(artifact);
+        Artifact x = factory.createArtifact();
+        x.setURI("foo/bar");
+        x = resolver.resolveModel(Artifact.class, x);
+        assertTrue(x == artifact);
+    }
+    
+    class Model {
+        private String name;
+        
+        Model(String name) {
+            this.name = name;
+        }
+        
+        @Override
+        public int hashCode() {
+            return name.hashCode();
+        }
+        
+        @Override
+        public boolean equals(Object obj) {
+            return name.equals(((Model)obj).name);
+        }
+    }
+
+}

Added: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/resolver/ExtensibleModelResolverTestCase.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/resolver/ExtensibleModelResolverTestCase.java?rev=648628&view=auto
==============================================================================
--- incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/resolver/ExtensibleModelResolverTestCase.java (added)
+++ incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/resolver/ExtensibleModelResolverTestCase.java Wed Apr 16 01:52:20 2008
@@ -0,0 +1,126 @@
+ /*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.tuscany.sca.contribution.resolver;
+
+import junit.framework.TestCase;
+
+import org.apache.tuscany.sca.contribution.Artifact;
+import org.apache.tuscany.sca.contribution.ContributionFactory;
+import org.apache.tuscany.sca.contribution.DefaultContributionFactory;
+import org.apache.tuscany.sca.contribution.DefaultModelFactoryExtensionPoint;
+import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint;
+
+/**
+ * Test DefaultArtifactResolver.
+ *
+ * @version $Rev: 618158 $ $Date: 2008-02-03 18:44:47 -0800 (Sun, 03 Feb 2008) $
+ */
+public class ExtensibleModelResolverTestCase extends TestCase {
+    private ExtensibleModelResolver resolver;
+    
+    private ContributionFactory factory;
+    
+    @Override
+    protected void setUp() throws Exception {
+        
+        ModelResolverExtensionPoint resolvers = new DefaultModelResolverExtensionPoint();
+        resolvers.addResolver(Model.class, TestModelResolver.class);
+        
+        ModelFactoryExtensionPoint factories = new DefaultModelFactoryExtensionPoint();
+        
+        resolver = new ExtensibleModelResolver(null, resolvers, factories, null);
+
+        factory = new DefaultContributionFactory();
+    }
+    
+    public void testResolvedDefault() {
+        OtherModel a = new OtherModel("a");
+        resolver.addModel(a);
+        OtherModel x = new OtherModel("a");
+        x = resolver.resolveModel(OtherModel.class, x);
+        assertTrue(x == a);
+    }
+
+    public void testResolvedRegisteredClass() {
+        Model a = new Model("a");
+        resolver.addModel(a);
+        Model x = new Model("a");
+        x = resolver.resolveModel(Model.class, x);
+        assertTrue(x == a);
+    }
+
+    public void testUnresolvedDefault() {
+        OtherModel x = new OtherModel("a");
+        OtherModel y = resolver.resolveModel(OtherModel.class, x);
+        assertTrue(x == y);
+    }
+    
+    public void testUnresolved() {
+        Model x = new Model("a");
+        Model y = resolver.resolveModel(Model.class, x);
+        assertTrue(x == y);
+    }
+    
+    public void testResolvedArtifact() {
+        Artifact artifact = factory.createArtifact();
+        artifact.setURI("foo/bar");
+        resolver.addModel(artifact);
+        Artifact x = factory.createArtifact();
+        x.setURI("foo/bar");
+        x = resolver.resolveModel(Artifact.class, x);
+        assertTrue(x == artifact);
+    }
+    
+    private class Model {
+        private String name;
+        
+        Model(String name) {
+            this.name = name;
+        }
+        
+        @Override
+        public int hashCode() {
+            return name.hashCode();
+        }
+        
+        @Override
+        public boolean equals(Object obj) {
+            return name.equals(((Model)obj).name);
+        }
+    }
+
+    private class OtherModel {
+        private String name;
+        
+        OtherModel(String name) {
+            this.name = name;
+        }
+        
+        @Override
+        public int hashCode() {
+            return name.hashCode();
+        }
+        
+        @Override
+        public boolean equals(Object obj) {
+            return name.equals(((OtherModel)obj).name);
+        }
+    }
+}

Added: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/resolver/TestModelResolver.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/resolver/TestModelResolver.java?rev=648628&view=auto
==============================================================================
--- incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/resolver/TestModelResolver.java (added)
+++ incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/resolver/TestModelResolver.java Wed Apr 16 01:52:20 2008
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.tuscany.sca.contribution.resolver;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tuscany.sca.contribution.Contribution;
+import org.apache.tuscany.sca.contribution.ModelFactoryExtensionPoint;
+
+/**
+ * A test implementation of a model resolver, based on a map.
+ * 
+ * @version $Rev: 618158 $ $Date: 2008-02-03 18:44:47 -0800 (Sun, 03 Feb 2008) $
+ */
+public class TestModelResolver implements ModelResolver {
+    
+    private Map<Object, Object> map = new HashMap<Object, Object>();
+    
+    public TestModelResolver(Contribution contribution, ModelFactoryExtensionPoint modelFactories) {
+    }
+    
+    public <T> T resolveModel(Class<T> modelClass, T unresolved) {
+        Object resolved = map.get(unresolved);
+        if (resolved != null) {
+            // Return the resolved object
+            return modelClass.cast(resolved);
+        } 
+        // Return the unresolved object
+        return unresolved;
+    }
+    
+    public void addModel(Object resolved) {
+        map.put(resolved, resolved);
+    }
+    
+    public Object removeModel(Object resolved) {
+        return map.remove(resolved);
+    }
+    
+}

Added: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/services/ContributionRepositoryTestCase.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/services/ContributionRepositoryTestCase.java?rev=648628&view=auto
==============================================================================
--- incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/services/ContributionRepositoryTestCase.java (added)
+++ incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/services/ContributionRepositoryTestCase.java Wed Apr 16 01:52:20 2008
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+
+package org.apache.tuscany.sca.contribution.services;
+
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+
+import javax.xml.stream.XMLInputFactory;
+
+import junit.framework.TestCase;
+
+import org.apache.tuscany.sca.contribution.service.impl.ContributionRepositoryImpl;
+import org.apache.tuscany.sca.contribution.service.util.FileHelper;
+
+public class ContributionRepositoryTestCase extends TestCase {
+    private ContributionRepositoryImpl repository;
+
+    @Override
+    protected void setUp() throws Exception {
+        // create repository (this should re-create the root directory)
+        this.repository = new ContributionRepositoryImpl("target/repository/", XMLInputFactory.newInstance());
+        repository.init();
+    }
+
+    public void testStore() throws Exception {
+        String resourceLocation = "/repository/sample-calculator.jar";
+        String contribution = "sample-calculator.jar";
+        URL contributionLocation = getClass().getResource(resourceLocation);
+        InputStream contributionStream = getClass().getResourceAsStream(resourceLocation);
+        repository.store(contribution, contributionLocation, contributionStream);
+
+        URL contributionURL = repository.find(contribution);
+        assertNotNull(contributionURL);
+    }
+
+    public void testRemove() throws Exception {
+        String resourceLocation = "/repository/sample-calculator.jar";
+        String contribution = "sample-calculator.jar";
+        URL contributionLocation = getClass().getResource(resourceLocation);
+        InputStream contributionStream = getClass().getResourceAsStream(resourceLocation);
+        repository.store(contribution, contributionLocation, contributionStream);
+
+        repository.remove(contribution);
+        URL contributionURL = repository.find(contribution);
+        assertNull(contributionURL);
+    }
+
+    public void testList() throws Exception {
+        String resourceLocation = "/repository/sample-calculator.jar";
+        String contribution = "sample-calculator.jar";
+        URL contributionLocation = getClass().getResource(resourceLocation);
+        InputStream contributionStream = getClass().getResourceAsStream(resourceLocation);
+        repository.store(contribution, contributionLocation, contributionStream);
+
+        assertEquals(1, repository.list().size());
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        FileHelper.deleteDirectory(new File("target/repository"));
+    }
+}

Added: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/services/PackageTypeDescriberImplTestCase.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/services/PackageTypeDescriberImplTestCase.java?rev=648628&view=auto
==============================================================================
--- incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/services/PackageTypeDescriberImplTestCase.java (added)
+++ incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/java/org/apache/tuscany/sca/contribution/services/PackageTypeDescriberImplTestCase.java Wed Apr 16 01:52:20 2008
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.tuscany.sca.contribution.services;
+
+import java.net.URL;
+
+import junit.framework.TestCase;
+
+import org.apache.tuscany.sca.contribution.PackageType;
+import org.apache.tuscany.sca.contribution.service.impl.PackageTypeDescriberImpl;
+
+public class PackageTypeDescriberImplTestCase extends TestCase {
+    private PackageTypeDescriberImpl packageTypeDescriber;
+
+    public void testResolveArchivePackageType() throws Exception {
+        URL artifactURL = getClass().getResource("/deployables/sample-calculator.jar");
+        assertEquals(PackageType.JAR, this.packageTypeDescriber.getType(artifactURL, null));
+    }
+
+    public void testResolveFolderPackageType() throws Exception {
+        URL artifactURL = getClass().getResource("/deployables/");
+        assertEquals(PackageType.FOLDER, this.packageTypeDescriber.getType(artifactURL, null));
+    }
+
+    public void testResolveFolder2PackageType() throws Exception {
+        URL artifactURL = getClass().getResource("/deployables");
+        assertEquals(PackageType.FOLDER, this.packageTypeDescriber.getType(artifactURL, null));
+    }
+
+    
+    public void testResolveUnknownPackageType() throws Exception {
+        URL artifactURL = getClass().getResource("/test.ext");
+        assertNull(this.packageTypeDescriber.getType(artifactURL, null));
+    }
+    
+    public void testDefaultPackageType() throws Exception {
+        URL artifactURL = getClass().getResource("/test.ext");
+        assertEquals("application/vnd.tuscany.ext", 
+                packageTypeDescriber.getType(artifactURL, "application/vnd.tuscany.ext"));        
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        packageTypeDescriber = new PackageTypeDescriberImpl();
+    }
+
+}

Added: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/resources/deployables/sample-calculator.jar
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/resources/deployables/sample-calculator.jar?rev=648628&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/resources/deployables/sample-calculator.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/resources/repository/sample-calculator.jar
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/resources/repository/sample-calculator.jar?rev=648628&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/resources/repository/sample-calculator.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/resources/test.composite
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/resources/test.composite?rev=648628&view=auto
==============================================================================
--- incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/resources/test.composite (added)
+++ incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/resources/test.composite Wed Apr 16 01:52:20 2008
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+-->
+<composite>
+    This file just needs to exist
+</composite>
\ No newline at end of file

Added: incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/resources/test.ext
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/contribution-impl/src/test/resources/test.ext?rev=648628&view=auto
==============================================================================
    (empty)

Modified: incubator/tuscany/sandbox/mobile-android/host-android/src/main/java/org/apache/tuscany/sca/host/embedded/SCADomain.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/host-android/src/main/java/org/apache/tuscany/sca/host/embedded/SCADomain.java?rev=648628&r1=648627&r2=648628&view=diff
==============================================================================
--- incubator/tuscany/sandbox/mobile-android/host-android/src/main/java/org/apache/tuscany/sca/host/embedded/SCADomain.java (original)
+++ incubator/tuscany/sandbox/mobile-android/host-android/src/main/java/org/apache/tuscany/sca/host/embedded/SCADomain.java Wed Apr 16 01:52:20 2008
@@ -24,6 +24,7 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.lang.reflect.Constructor;
+import java.net.MalformedURLException;
 import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
@@ -88,7 +89,7 @@
      * @return
      */
     public static SCADomain newInstance(Context context, String composite) {
-        return createNewInstance(context, LOCAL_DOMAIN_URI, "dex:/" + context.getPackageName() + "/raw/", composite);
+    	return createNewInstance(context, LOCAL_DOMAIN_URI, "dex://" + context.getPackageName() + "/raw/", composite);
     }
     
     /**

Modified: incubator/tuscany/sandbox/mobile-android/host-android/src/main/java/org/apache/tuscany/sca/host/embedded/impl/DefaultSCADomain.java
URL: http://svn.apache.org/viewvc/incubator/tuscany/sandbox/mobile-android/host-android/src/main/java/org/apache/tuscany/sca/host/embedded/impl/DefaultSCADomain.java?rev=648628&r1=648627&r2=648628&view=diff
==============================================================================
--- incubator/tuscany/sandbox/mobile-android/host-android/src/main/java/org/apache/tuscany/sca/host/embedded/impl/DefaultSCADomain.java (original)
+++ incubator/tuscany/sandbox/mobile-android/host-android/src/main/java/org/apache/tuscany/sca/host/embedded/impl/DefaultSCADomain.java Wed Apr 16 01:52:20 2008
@@ -359,31 +359,8 @@
      */
     protected URL getContributionLocation(ClassLoader classLoader, String contributionPath, String[] composites)
         throws MalformedURLException {
-    
-        int colonIndex = contributionPath.indexOf(':');
-        String protocol;
-        
-        if (colonIndex == -1) {
-        	throw new IllegalArgumentException("can't determine the protocol!");
-        	
-        } else {
-        	protocol = contributionPath.substring(0, colonIndex);
-        }
-        
-        int slashIndex = contributionPath.indexOf('/');
-        
-        if (slashIndex == -1 || slashIndex == contributionPath.length()) {
-        	throw new IllegalArgumentException("can't determine the host!");
-        }
-        
-        String host = contributionPath.substring(slashIndex + 1);
-        slashIndex = host.indexOf('/');
-        
-        if (slashIndex != -1) {
-        	host = host.substring(0, slashIndex);
-        }
-        
-        return new URL(protocol, host, "");
+    	
+    	return new URL(contributionPath);
         
     }
 



---------------------------------------------------------------------
To unsubscribe, e-mail: tuscany-commits-unsubscribe@ws.apache.org
For additional commands, e-mail: tuscany-commits-help@ws.apache.org