You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by br...@apache.org on 2007/08/29 04:43:59 UTC

svn commit: r570618 [3/14] - in /maven/sandbox/trunk/archetypeng: ./ archetype-common/ archetype-common/src/ archetype-common/src/main/ archetype-common/src/main/java/ archetype-common/src/main/java/org/ archetype-common/src/main/java/org/apache/ arche...

Added: maven/sandbox/trunk/archetypeng/archetype-common/src/main/java/org/apache/maven/archetype/common/DefaultPomManager.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/archetypeng/archetype-common/src/main/java/org/apache/maven/archetype/common/DefaultPomManager.java?rev=570618&view=auto
==============================================================================
--- maven/sandbox/trunk/archetypeng/archetype-common/src/main/java/org/apache/maven/archetype/common/DefaultPomManager.java (added)
+++ maven/sandbox/trunk/archetypeng/archetype-common/src/main/java/org/apache/maven/archetype/common/DefaultPomManager.java Tue Aug 28 19:43:33 2007
@@ -0,0 +1,455 @@
+/*
+ * 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.maven.archetype.common;
+
+import org.apache.maven.archetype.exception.InvalidPackaging;
+import org.apache.maven.model.Build;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Parent;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.ReportPlugin;
+import org.apache.maven.model.Reporting;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
+
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import org.dom4j.Node;
+
+import org.dom4j.io.SAXReader;
+import org.dom4j.io.XMLWriter;
+
+import org.jdom.JDOMException;
+
+import org.jdom.input.SAXBuilder;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @plexus.component
+ */
+public class DefaultPomManager
+extends AbstractLogEnabled
+implements PomManager
+{
+    public void addModule ( File pom, String artifactId )
+    throws FileNotFoundException,
+        IOException,
+        XmlPullParserException,
+        DocumentException,
+        InvalidPackaging
+    {
+        boolean found = false;
+
+        StringWriter writer = new StringWriter ();
+        Reader fileReader = new FileReader ( pom );
+
+        try
+        {
+            fileReader = new FileReader ( pom );
+
+            SAXReader reader = new SAXReader ();
+            Document document = reader.read ( fileReader );
+            Element project = document.getRootElement ();
+
+            String packaging = null;
+            Element packagingElement = project.element ( "packaging" );
+            if ( packagingElement != null )
+            {
+                packaging = packagingElement.getStringValue ();
+            }
+            if ( !"pom".equals ( packaging ) )
+            {
+                throw new InvalidPackaging (
+                    "Unable to add module to the current project as it is not of packaging type 'pom'"
+                );
+            }
+
+            Element modules = project.element ( "modules" );
+            if ( modules == null )
+            {
+                modules = project.addText ( "  " ).addElement ( "modules" );
+                modules.setText ( "\n  " );
+                project.addText ( "\n" );
+            }
+            // TODO: change to while loop
+            for ( Iterator i = modules.elementIterator ( "module" ); i.hasNext () && !found; )
+            {
+                Element module = (Element) i.next ();
+                if ( module.getText ().equals ( artifactId ) )
+                {
+                    found = true;
+                }
+            }
+            if ( !found )
+            {
+                Node lastTextNode = null;
+                for ( Iterator i = modules.nodeIterator (); i.hasNext (); )
+                {
+                    Node node = (Node) i.next ();
+                    if ( node.getNodeType () == Node.ELEMENT_NODE )
+                    {
+                        lastTextNode = null;
+                    }
+                    else if ( node.getNodeType () == Node.TEXT_NODE )
+                    {
+                        lastTextNode = node;
+                    }
+                }
+
+                if ( lastTextNode != null )
+                {
+                    modules.remove ( lastTextNode );
+                }
+
+                modules.addText ( "\n    " );
+                modules.addElement ( "module" ).setText ( artifactId );
+                modules.addText ( "\n  " );
+
+                XMLWriter xmlWriter = new XMLWriter ( writer );
+                xmlWriter.write ( document );
+
+                FileUtils.fileWrite ( pom.getAbsolutePath (), writer.toString () );
+            } // end if
+        }
+        finally
+        {
+            IOUtil.close ( fileReader );
+        }
+    }
+
+    public void addParent ( File pom, File parentPom )
+    throws FileNotFoundException, IOException, XmlPullParserException
+    {
+        Model generatedModel = readPom ( pom );
+
+        Model parentModel = readPom ( parentPom );
+
+        Parent parent = new Parent ();
+        parent.setGroupId ( parentModel.getGroupId () );
+        if ( parent.getGroupId () == null )
+        {
+            parent.setGroupId ( parentModel.getParent ().getGroupId () );
+        }
+        parent.setArtifactId ( parentModel.getArtifactId () );
+        parent.setVersion ( parentModel.getVersion () );
+        if ( parent.getVersion () == null )
+        {
+            parent.setVersion ( parentModel.getParent ().getVersion () );
+        }
+        generatedModel.setParent ( parent );
+
+        writePom ( generatedModel, pom );
+    }
+
+    public void mergePoms ( File pom, File temporaryPom )
+    throws FileNotFoundException, IOException, XmlPullParserException
+    {
+        Model model = readPom ( pom );
+        Model generatedModel = readPom ( temporaryPom );
+        mergeDependencies ( model, generatedModel );
+        mergeBuildPlugins ( model, generatedModel );
+        mergeReportPlugins ( model, generatedModel );
+
+//
+//        // Potential merging
+//
+//        model.getModelEncoding ();
+//        model.getModelVersion ();
+//
+//        model.getGroupId ();
+//        model.getArtifactId ();
+//        model.getVersion ();
+//        model.getParent ();
+//
+//        model.getId ();
+//        model.getName ();
+//        model.getInceptionYear ();
+//        model.getDescription ();
+//        model.getUrl ();
+//        model.getLicenses ();
+//        model.getProperties ();
+//
+//        model.getOrganization ();
+//        model.getMailingLists ();
+//        model.getContributors ();
+//        model.getDevelopers ();
+//
+//        model.getScm ();
+//        model.getCiManagement ();
+//        model.getDistributionManagement ();
+//        model.getIssueManagement ();
+//
+//        model.getPackaging ();
+////        model.getDependencies (); // done
+//        model.getDependencyManagement ();
+//        model.getPrerequisites ().getMaven ();
+//        model.getPrerequisites ().getModelEncoding ();
+//
+//        model.getProfiles ();
+//        model.getModules ();
+//        model.getRepositories ();
+//        model.getPluginRepositories ();
+//
+//        model.getBuild ().getDefaultGoal ();
+//        model.getBuild ().getFinalName ();
+//        model.getBuild ().getModelEncoding ();
+//        model.getBuild ().getFilters ();
+//        model.getBuild ().getDirectory ();
+//        model.getBuild ().getOutputDirectory ();
+//        model.getBuild ().getSourceDirectory ();
+//        model.getBuild ().getResources ();
+//        model.getBuild ().getScriptSourceDirectory ();
+//        model.getBuild ().getTestOutputDirectory ();
+//        model.getBuild ().getTestResources ();
+//        model.getBuild ().getTestSourceDirectory ();
+//        model.getBuild ().getPluginManagement ();
+//        model.getBuild ().getExtensions ();
+////        model.getBuild ().getPluginsAsMap (); // done
+//
+//        model.getReporting ().getModelEncoding ();
+//        model.getReporting ().getOutputDirectory ();
+////        model.getReporting ().getReportPluginsAsMap (); // done
+//
+
+        writePom ( model, pom );
+    }
+
+    public Model readPom ( final File pomFile )
+    throws FileNotFoundException, IOException, XmlPullParserException
+    { // TODO ensure correct encoding by using default one from method argument !!!
+
+        Model model;
+        Reader pomReader = null;
+        try
+        {
+            FileCharsetDetector detector = new FileCharsetDetector ( pomFile );
+
+            String fileEncoding = detector.isFound () ? detector.getCharset () : "UTF-8";
+
+            pomReader = new InputStreamReader ( new FileInputStream ( pomFile ), fileEncoding );
+
+            MavenXpp3Reader reader = new MavenXpp3Reader ();
+
+            model = reader.read ( pomReader );
+
+            if ( StringUtils.isEmpty ( model.getModelEncoding () ) )
+            {
+                model.setModelEncoding ( fileEncoding );
+            }
+        }
+        finally
+        {
+            IOUtil.close ( pomReader );
+            pomReader = null;
+        }
+        return model;
+    }
+
+    public void writePom ( final Model model, final File pomFile )
+    throws IOException
+    {
+        InputStream inputStream = null;
+        Writer outputStreamWriter = null;
+//        FileCharsetDetector detector = new FileCharsetDetector ( pomFile );
+
+        String fileEncoding =
+            StringUtils.isEmpty ( model.getModelEncoding () ) ? model.getModelEncoding () : "UTF-8";
+
+        try
+        {
+            inputStream = new FileInputStream ( pomFile );
+
+            SAXBuilder builder = new SAXBuilder ();
+            org.jdom.Document doc = builder.build ( inputStream );
+            inputStream.close ();
+            inputStream = null;
+
+            MavenJDOMWriter writer = new MavenJDOMWriter ();
+
+            outputStreamWriter =
+                new OutputStreamWriter ( new FileOutputStream ( pomFile ), fileEncoding );
+
+            org.jdom.output.Format form =
+                org.jdom.output.Format.getRawFormat ().setEncoding ( fileEncoding );
+            writer.write ( model, doc, outputStreamWriter, form );
+            outputStreamWriter.close ();
+            outputStreamWriter = null;
+        }
+        catch ( JDOMException exc )
+        {
+            throw (IOException) new IOException ( "Cannot parse the POM by JDOM." );
+        }
+        catch ( FileNotFoundException e )
+        {
+            getLogger ().debug ( "Creating pom file " + pomFile );
+
+            Writer pomWriter = null;
+
+            try
+            {
+//                pomWriter = new FileWriter ( pomFile );
+                pomWriter =
+                    new OutputStreamWriter ( new FileOutputStream ( pomFile ), fileEncoding );
+
+                MavenXpp3Writer writer = new MavenXpp3Writer ();
+                writer.write ( pomWriter, model );
+                pomWriter.close ();
+                pomWriter = null;
+            }
+            finally
+            {
+                IOUtil.close ( pomWriter );
+            }
+        }
+        finally
+        {
+            IOUtil.close ( inputStream );
+            IOUtil.close ( outputStreamWriter );
+        }
+    }
+
+    private Map createDependencyMap ( List dependencies )
+    {
+        Map dependencyMap = new HashMap ();
+        Iterator dependenciesIterator = dependencies.iterator ();
+        while ( dependenciesIterator.hasNext () )
+        {
+            Dependency dependency = (Dependency) dependenciesIterator.next ();
+
+            dependencyMap.put (
+                dependency.getGroupId () + ":" + dependency.getArtifactId (),
+                dependency
+            );
+        }
+
+        return dependencyMap;
+    }
+
+    private void mergeBuildPlugins ( Model model, Model generatedModel )
+    {
+        if ( generatedModel.getBuild () != null )
+        {
+            if ( model.getBuild () == null )
+            {
+                model.setBuild ( new Build () );
+            }
+
+            Map pluginsByIds = model.getBuild ().getPluginsAsMap ();
+            Map generatedPluginsByIds = generatedModel.getBuild ().getPluginsAsMap ();
+
+            Iterator generatedPluginsIds = generatedPluginsByIds.keySet ().iterator ();
+            while ( generatedPluginsIds.hasNext () )
+            {
+                String generatedPluginsId = (String) generatedPluginsIds.next ();
+
+                if ( !pluginsByIds.containsKey ( generatedPluginsId ) )
+                {
+                    model.getBuild ().addPlugin (
+                        (Plugin) generatedPluginsByIds.get ( generatedPluginsId )
+                    );
+                }
+                else
+                {
+                    getLogger ().warn ( "Can not override plugin: " + generatedPluginsId );
+                }
+            }
+        }
+    }
+
+    private void mergeDependencies ( Model model, Model generatedModel )
+    {
+        Map dependenciesByIds = createDependencyMap ( model.getDependencies () );
+        Map generatedDependenciesByIds = createDependencyMap ( generatedModel.getDependencies () );
+
+        Iterator generatedDependencyIds = generatedDependenciesByIds.keySet ().iterator ();
+        while ( generatedDependencyIds.hasNext () )
+        {
+            String generatedDependencyId = (String) generatedDependencyIds.next ();
+
+            if ( !dependenciesByIds.containsKey ( generatedDependencyId ) )
+            {
+                model.addDependency (
+                    (Dependency) generatedDependenciesByIds.get ( generatedDependencyId )
+                );
+            }
+            else
+            {
+                getLogger ().warn ( "Can not override property: " + generatedDependencyId );
+            }
+        }
+    }
+
+    private void mergeReportPlugins ( Model model, Model generatedModel )
+    {
+        if ( generatedModel.getReporting () != null )
+        {
+            if ( model.getReporting () == null )
+            {
+                model.setReporting ( new Reporting () );
+            }
+
+            Map reportPluginsByIds = model.getReporting ().getReportPluginsAsMap ();
+            Map generatedReportPluginsByIds =
+                generatedModel.getReporting ().getReportPluginsAsMap ();
+
+            Iterator generatedReportPluginsIds = generatedReportPluginsByIds.keySet ().iterator ();
+            while ( generatedReportPluginsIds.hasNext () )
+            {
+                String generatedReportPluginsId = (String) generatedReportPluginsIds.next ();
+
+                if ( !reportPluginsByIds.containsKey ( generatedReportPluginsId ) )
+                {
+                    model.getReporting ().addPlugin (
+                        (ReportPlugin) generatedReportPluginsByIds.get ( generatedReportPluginsId )
+                    );
+                }
+                else
+                {
+                    getLogger ().warn ( "Can not override report: " + generatedReportPluginsId );
+                }
+            }
+        }
+    }
+}

Added: maven/sandbox/trunk/archetypeng/archetype-common/src/main/java/org/apache/maven/archetype/common/FileCharsetDetector.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/archetypeng/archetype-common/src/main/java/org/apache/maven/archetype/common/FileCharsetDetector.java?rev=570618&view=auto
==============================================================================
--- maven/sandbox/trunk/archetypeng/archetype-common/src/main/java/org/apache/maven/archetype/common/FileCharsetDetector.java (added)
+++ maven/sandbox/trunk/archetypeng/archetype-common/src/main/java/org/apache/maven/archetype/common/FileCharsetDetector.java Tue Aug 28 19:43:33 2007
@@ -0,0 +1,114 @@
+/*
+ * 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.maven.archetype.common;
+
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+
+import org.mozilla.intl.chardet.nsDetector;
+import org.mozilla.intl.chardet.nsICharsetDetectionObserver;
+import org.mozilla.intl.chardet.nsPSMDetector;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+/**
+ * @author  rafale
+ */
+public class FileCharsetDetector
+extends AbstractLogEnabled
+{
+    private String charset = null;
+
+    private boolean found = false;
+
+    public FileCharsetDetector ( File detectedFile )
+    throws FileNotFoundException, IOException
+    {
+        nsDetector det = new nsDetector ( nsPSMDetector.ALL );
+
+        det.Init (
+            new nsICharsetDetectionObserver ()
+            {
+                public void Notify ( String charset )
+                {
+                    FileCharsetDetector.this.charset = charset;
+                    FileCharsetDetector.this.found = true;
+                }
+            }
+        );
+
+        BufferedInputStream imp = new BufferedInputStream ( new FileInputStream ( detectedFile ) );
+
+        byte[] buf = new byte[1024];
+        int len;
+        boolean done = false;
+        boolean isAscii = true;
+
+        while ( ( len = imp.read ( buf, 0, buf.length ) ) != -1 )
+        {
+            // Check if the stream is only ascii.
+            if ( isAscii )
+            {
+                isAscii = det.isAscii ( buf, len );
+            }
+
+            // DoIt if non-ascii and not done yet.
+            if ( !isAscii && !done )
+            {
+                done = det.DoIt ( buf, len, false );
+                found = done;
+            }
+        }
+        det.DataEnd ();
+
+        if ( !isFound () )
+        {
+            String[] prob = det.getProbableCharsets ();
+
+//            if ( Arrays.asList ( prob ).contains ( "windows-1252" ) )
+//            {
+//                charset = "ISO-8859-1";
+//            }
+//            else
+            if ( prob.length > 0 )
+            {
+                charset = prob[0];
+            }
+        }
+
+        if ( isAscii )
+        {
+            charset = "ASCII";
+        }
+    }
+
+    public String getCharset ()
+    {
+        return charset;
+    }
+
+    public boolean isFound ()
+    {
+        return found;
+    }
+}

Added: maven/sandbox/trunk/archetypeng/archetype-common/src/main/java/org/apache/maven/archetype/common/ListScanner.java
URL: http://svn.apache.org/viewvc/maven/sandbox/trunk/archetypeng/archetype-common/src/main/java/org/apache/maven/archetype/common/ListScanner.java?rev=570618&view=auto
==============================================================================
--- maven/sandbox/trunk/archetypeng/archetype-common/src/main/java/org/apache/maven/archetype/common/ListScanner.java (added)
+++ maven/sandbox/trunk/archetypeng/archetype-common/src/main/java/org/apache/maven/archetype/common/ListScanner.java Tue Aug 28 19:43:33 2007
@@ -0,0 +1,568 @@
+/*
+ * 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.maven.archetype.common;
+
+import org.codehaus.plexus.util.SelectorUtils;
+import org.codehaus.plexus.util.StringUtils;
+
+import java.io.File;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Class for scanning a directory for files/directories which match certain criteria.
+ *
+ * <p>These criteria consist of selectors and patterns which have been specified. With the selectors
+ * you can select which files you want to have included. Files which are not selected are excluded.
+ * With patterns you can include or exclude files based on their filename.</p>
+ *
+ * <p>The idea is simple. A given directory is recursively scanned for all files and directories.
+ * Each file/directory is matched against a set of selectors, including special support for matching
+ * against filenames with include and and exclude patterns. Only files/directories which match at
+ * least one pattern of the include pattern list or other file selector, and don't match any pattern
+ * of the exclude pattern list or fail to match against a required selector will be placed in the
+ * list of files/directories found.</p>
+ *
+ * <p>When no list of include patterns is supplied, "**" will be used, which means that everything
+ * will be matched. When no list of exclude patterns is supplied, an empty list is used, such that
+ * nothing will be excluded. When no selectors are supplied, none are applied.</p>
+ *
+ * <p>The filename pattern matching is done as follows: The name to be matched is split up in path
+ * segments. A path segment is the name of a directory or file, which is bounded by <code>
+ * File.separator</code> ('/' under UNIX, '\' under Windows). For example, "abc/def/ghi/xyz.java" is
+ * split up in the segments "abc", "def","ghi" and "xyz.java". The same is done for the pattern
+ * against which should be matched.</p>
+ *
+ * <p>The segments of the name and the pattern are then matched against each other. When '**' is
+ * used for a path segment in the pattern, it matches zero or more path segments of the name.</p>
+ *
+ * <p>There is a special case regarding the use of <code>File.separator</code>s at the beginning of
+ * the pattern and the string to match:<br>
+ * When a pattern starts with a <code>File.separator</code>, the string to match must also start
+ * with a <code>File.separator</code>. When a pattern does not start with a <code>
+ * File.separator</code>, the string to match may not start with a <code>File.separator</code>. When
+ * one of these rules is not obeyed, the string will not match.</p>
+ *
+ * <p>When a name path segment is matched against a pattern path segment, the following special
+ * characters can be used:<br>
+ * '*' matches zero or more characters<br>
+ * '?' matches one character.</p>
+ *
+ * <p>Examples:</p>
+ *
+ * <p>"**\*.class" matches all .class files/dirs in a directory tree.</p>
+ *
+ * <p>"test\a??.java" matches all files/dirs which start with an 'a', then two more characters and
+ * then ".java", in a directory called test.</p>
+ *
+ * <p>"**" matches everything in a directory tree.</p>
+ *
+ * <p>"**\test\**\XYZ*" matches all files/dirs which start with "XYZ" and where there is a parent
+ * directory called test (e.g. "abc\test\def\ghi\XYZ123").</p>
+ *
+ * <p>Case sensitivity may be turned off if necessary. By default, it is turned on.</p>
+ *
+ * <p>Example of usage:</p>
+ *
+ * <pre>
+     String[] includes = {"**\\*.class"};
+     String[] excludes = {"modules\\*\\**"};
+     ds.setIncludes(includes);
+     ds.setExcludes(excludes);
+     ds.setBasedir(new File("test"));
+     ds.setCaseSensitive(true);
+     ds.scan();
+
+     System.out.println("FILES:");
+     String[] files = ds.getIncludedFiles();
+     for (int i = 0; i < files.length; i++) {
+       System.out.println(files[i]);
+     }
+ * </pre>
+ *
+ * <p>This will scan a directory called test for .class files, but excludes all files in all proper
+ * subdirectories of a directory called "modules"</p>
+ *
+ * <p>This class was stealed from rg.coudehaus.plexus.util.DirectoryScanner and adapted to search
+ * from a List<String></p>
+ *
+ * @author  Arnout J. Kuiper <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a>
+ * @author  Magesh Umasankar
+ * @author  <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
+ * @author  <a href="mailto:levylambert@tiscali-dsl.de">Antoine Levy-Lambert</a>
+ */
+public class ListScanner
+{
+    /**
+     * Patterns which should be excluded by default.
+     *
+     * @see  #addDefaultExcludes()
+     */
+    public static final String[] DEFAULTEXCLUDES =
+    { // Miscellaneous typical temporary files
+        "**/*~", "**/#*#", "**/.#*", "**/%*%", "**/._*",
+
+        // CVS
+        "**/CVS", "**/CVS/**", "**/.cvsignore",
+
+        // SCCS
+        "**/SCCS", "**/SCCS/**",
+
+        // Visual SourceSafe
+        "**/vssver.scc",
+
+        // Subversion
+        "**/.svn", "**/.svn/**",
+
+        // Arch
+        "**/.arch-ids", "**/.arch-ids/**",
+
+        // Bazaar
+        "**/.bzr", "**/.bzr/**",
+
+        // SurroundSCM
+        "**/.MySCMServerInfo",
+
+        // Mac
+        "**/.DS_Store"
+    };
+
+    /**
+     * The base directory to be scanned.
+     */
+    protected String basedir;
+
+    /**
+     * Whether or not everything tested so far has been included.
+     */
+    protected boolean everythingIncluded = true;
+
+    /**
+     * The patterns for the files to be excluded.
+     */
+    protected String[] excludes;
+
+    /**
+     * The patterns for the files to be included.
+     */
+    protected String[] includes;
+
+    /**
+     * Whether or not the file system should be treated as a case sensitive one.
+     */
+    protected boolean isCaseSensitive = true;
+
+    /**
+     * Sole constructor.
+     */
+    public ListScanner ()
+    { }
+
+    public static String getDefaultExcludes ()
+    {
+        return StringUtils.join ( DEFAULTEXCLUDES, "," );
+    }
+
+    /**
+     * Tests whether or not a string matches against a pattern. The pattern may contain two special
+     * characters:<br>
+     * '*' means zero or more characters<br>
+     * '?' means one and only one character
+     *
+     * @param   pattern  The pattern to match against. Must not be <code>null</code>.
+     * @param   str      The string which must be matched against the pattern. Must not be <code>
+     *                   null</code>.
+     *
+     * @return  <code>true</code> if the string matches against the pattern, or <code>false</code>
+     *          otherwise.
+     */
+    public static boolean match ( String pattern, String str )
+    {
+        // default matches the SelectorUtils default
+        return match ( pattern, str, true );
+    }
+
+    /**
+     * Tests whether or not a string matches against a pattern. The pattern may contain two special
+     * characters:<br>
+     * '*' means zero or more characters<br>
+     * '?' means one and only one character
+     *
+     * @param   pattern          The pattern to match against. Must not be <code>null</code>.
+     * @param   str              The string which must be matched against the pattern. Must not be
+     *                           <code>null</code>.
+     * @param   isCaseSensitive  Whether or not matching should be performed case sensitively.
+     *
+     * @return  <code>true</code> if the string matches against the pattern, or <code>false</code>
+     *          otherwise.
+     */
+    protected static boolean match ( String pattern, String str, boolean isCaseSensitive )
+    {
+        return SelectorUtils.match ( pattern, str, isCaseSensitive );
+    }
+
+    /**
+     * Tests whether or not a given path matches a given pattern.
+     *
+     * @param   pattern  The pattern to match against. Must not be <code>null</code>.
+     * @param   str      The path to match, as a String. Must not be <code>null</code>.
+     *
+     * @return  <code>true</code> if the pattern matches against the string, or <code>false</code>
+     *          otherwise.
+     */
+    protected static boolean matchPath ( String pattern, String str )
+    {
+        // default matches the SelectorUtils default
+        return matchPath ( pattern, str, true );
+    }
+
+    /**
+     * Tests whether or not a given path matches a given pattern.
+     *
+     * @param   pattern          The pattern to match against. Must not be <code>null</code>.
+     * @param   str              The path to match, as a String. Must not be <code>null</code>.
+     * @param   isCaseSensitive  Whether or not matching should be performed case sensitively.
+     *
+     * @return  <code>true</code> if the pattern matches against the string, or <code>false</code>
+     *          otherwise.
+     */
+    protected static boolean matchPath ( String pattern, String str, boolean isCaseSensitive )
+    {
+        return
+            SelectorUtils.matchPath (
+                PathUtils.convertPathForOS ( pattern ),
+                PathUtils.convertPathForOS ( str ),
+                isCaseSensitive
+            );
+    }
+
+    /**
+     * Tests whether or not a given path matches the start of a given pattern up to the first "**".
+     *
+     * <p>This is not a general purpose test and should only be used if you can live with false
+     * positives. For example, <code>pattern=**\a</code> and <code>str=b</code> will yield <code>
+     * true</code>.</p>
+     *
+     * @param   pattern  The pattern to match against. Must not be <code>null</code>.
+     * @param   str      The path to match, as a String. Must not be <code>null</code>.
+     *
+     * @return  whether or not a given path matches the start of a given pattern up to the first
+     *          "**".
+     */
+    protected static boolean matchPatternStart ( String pattern, String str )
+    {
+        // default matches SelectorUtils default
+        return matchPatternStart ( pattern, str, true );
+    }
+
+    /**
+     * Tests whether or not a given path matches the start of a given pattern up to the first "**".
+     *
+     * <p>This is not a general purpose test and should only be used if you can live with false
+     * positives. For example, <code>pattern=**\a</code> and <code>str=b</code> will yield <code>
+     * true</code>.</p>
+     *
+     * @param   pattern          The pattern to match against. Must not be <code>null</code>.
+     * @param   str              The path to match, as a String. Must not be <code>null</code>.
+     * @param   isCaseSensitive  Whether or not matching should be performed case sensitively.
+     *
+     * @return  whether or not a given path matches the start of a given pattern up to the first
+     *          "**".
+     */
+    protected static boolean matchPatternStart (
+        String pattern,
+        String str,
+        boolean isCaseSensitive
+    )
+    {
+        return
+            SelectorUtils.matchPatternStart (
+                PathUtils.convertPathForOS ( pattern ),
+                PathUtils.convertPathForOS ( str ),
+                isCaseSensitive
+            );
+    }
+
+    /**
+     * Adds default exclusions to the current exclusions set.
+     */
+    public void addDefaultExcludes ()
+    {
+        int excludesLength = ( excludes == null ) ? 0 : excludes.length;
+        String[] newExcludes;
+        newExcludes = new String[excludesLength + DEFAULTEXCLUDES.length];
+        if ( excludesLength > 0 )
+        {
+            System.arraycopy ( excludes, 0, newExcludes, 0, excludesLength );
+        }
+        for ( int i = 0; i < DEFAULTEXCLUDES.length; i++ )
+        {
+            newExcludes[i + excludesLength] =
+                DEFAULTEXCLUDES[i].replace ( '/', File.separatorChar ).replace (
+                    '\\',
+                    File.separatorChar
+                );
+        }
+        excludes = newExcludes;
+    }
+
+    /**
+     * Returns the base directory to be scanned. This is the directory which is scanned recursively.
+     *
+     * @return  the base directory to be scanned
+     */
+    public String getBasedir ()
+    {
+        return basedir;
+    }
+
+    /**
+     * Sets the base directory to be scanned. This is the directory which is scanned recursively.
+     * This directory is normalized for multiple os's (all / and \\ are replaced with
+     * File.separatorChar
+     *
+     * @param  basedir  The base directory for scanning. Should not be <code>null</code>.
+     */
+    public void setBasedir ( String basedir )
+    {
+        this.basedir = basedir;
+    }
+
+    /**
+     * Sets whether or not the file system should be regarded as case sensitive.
+     *
+     * @param  isCaseSensitive  whether or not the file system should be regarded as a case
+     *                          sensitive one
+     */
+    public void setCaseSensitive ( boolean isCaseSensitive )
+    {
+        this.isCaseSensitive = isCaseSensitive;
+    }
+
+    /**
+     * Sets the list of exclude patterns to use. All '/' and '\' characters are replaced by <code>
+     * File.separatorChar</code>, so the separator used need not match <code>
+     * File.separatorChar</code>.
+     *
+     * <p>When a pattern ends with a '/' or '\', "**" is appended.</p>
+     *
+     * @param  excludes  A list of exclude patterns. May be <code>null</code>, indicating that no
+     *                   files should be excluded. If a non-<code>null</code> list is given, all
+     *                   elements must be non-<code>null</code>.
+     */
+    public void setExcludes ( List excludesList )
+    {
+        String[] excludes = (String[]) excludesList.toArray ( new String[excludesList.size ()] );
+        if ( excludes == null )
+        {
+            this.excludes = null;
+        }
+        else
+        {
+            setExcludes ( excludes );
+        }
+    }
+
+    public void setExcludes ( String excludes )
+    {
+        if ( excludes == null )
+        {
+            this.excludes = null;
+        }
+        else
+        {
+            setExcludes ( StringUtils.split ( excludes, "," ) );
+        }
+    }
+
+    /**
+     * Sets the list of include patterns to use. All '/' and '\' characters are replaced by <code>
+     * File.separatorChar</code>, so the separator used need not match <code>
+     * File.separatorChar</code>.
+     *
+     * <p>When a pattern ends with a '/' or '\', "**" is appended.</p>
+     *
+     * @param  includes  A list of include patterns. May be <code>null</code>, indicating that all
+     *                   files should be included. If a non-<code>null</code> list is given, all
+     *                   elements must be non-<code>null</code>.
+     */
+    public void setIncludes ( List includesList )
+    {
+        String[] includes = (String[]) includesList.toArray ( new String[includesList.size ()] );
+        if ( includes == null )
+        {
+            this.includes = null;
+        }
+        else
+        {
+            setIncludes ( includes );
+        }
+    }
+
+    public void setIncludes ( String includes )
+    {
+        if ( includes == null )
+        {
+            this.includes = null;
+        }
+        else
+        {
+            setIncludes ( StringUtils.split ( includes, "," ) );
+        }
+    }
+
+    /**
+     * Scans the base directory for files which match at least one include pattern and don't match
+     * any exclude patterns. If there are selectors then the files must pass muster there, as well.
+     *
+     * @exception  IllegalStateException  if the base directory was set incorrectly (i.e. if it is
+     *                                    <code>null</code>, doesn't exist, or isn't a directory).
+     */
+    public List scan ( List files )
+    throws IllegalStateException
+    {
+//        System.err.println("Scanning \nbasedir="+basedir +
+//                " \nincludes=" + java.util.Arrays.toString(includes) +
+//                " \nexcludes=" + java.util.Arrays.toString(excludes) +
+//                " \non files="+files);
+        if ( basedir == null )
+        {
+            throw new IllegalStateException ( "No basedir set" );
+        }
+
+        if ( includes == null )
+        {
+            // No includes supplied, so set it to 'matches all'
+            includes = new String[1];
+            includes[0] = "**";
+        }
+        if ( excludes == null )
+        {
+            excludes = new String[0];
+        }
+
+        List result = new ArrayList ();
+
+        Iterator iterator = files.iterator ();
+        while ( iterator.hasNext () )
+        {
+            String fileName = (String) iterator.next ();
+//            System.err.println("Checking "+(isIncluded ( fileName )?"I":"-")+(isExcluded ( fileName )?"E":"-")+fileName);
+            if ( isIncluded ( fileName ) && !isExcluded ( fileName ) )
+            {
+                result.add ( fileName );
+            }
+        }
+//        System.err.println("Result "+result+"\n\n\n");
+        return result;
+    }
+
+    /**
+     * Tests whether or not a name matches against at least one exclude pattern.
+     *
+     * @param   name  The name to match. Must not be <code>null</code>.
+     *
+     * @return  <code>true</code> when the name matches against at least one exclude pattern, or
+     *          <code>false</code> otherwise.
+     */
+    protected boolean isExcluded ( String name )
+    {
+        return matchesPatterns ( name, excludes );
+    }
+
+    /**
+     * Tests whether or not a name matches against at least one include pattern.
+     *
+     * @param   name  The name to match. Must not be <code>null</code>.
+     *
+     * @return  <code>true</code> when the name matches against at least one include pattern, or
+     *          <code>false</code> otherwise.
+     */
+    protected boolean isIncluded ( String name )
+    {
+        return matchesPatterns ( name, includes );
+    }
+
+    /**
+     * Tests whether or not a name matches against at least one include pattern.
+     *
+     * @param   name      The name to match. Must not be <code>null</code>.
+     * @param   patterns  The list of patterns to match.
+     *
+     * @return  <code>true</code> when the name matches against at least one include pattern, or
+     *          <code>false</code> otherwise.
+     */
+    protected boolean matchesPatterns ( String name, String[] patterns )
+    {
+        // avoid extra object creation in the loop
+        String path = null;
+
+        String baseDir = getBasedir ();
+        if ( baseDir.length () > 0 )
+        {
+            baseDir = baseDir.concat ( File.separator );
+        }
+
+        for ( int i = 0; i < patterns.length; i++ )
+        {
+            path = PathUtils.convertPathForOS ( baseDir + patterns[i] );
+//            System.err.println("path="+path);
+            if ( matchPath ( path, name, isCaseSensitive ) )
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void setExcludes ( String[] excludes )
+    {
+        this.excludes = setPatterns ( excludes );
+    }
+
+    private void setIncludes ( String[] includes )
+    {
+        this.includes = setPatterns ( includes );
+    }
+
+    private String[] setPatterns ( String[] patterns )
+    {
+        String[] result = null;
+        if ( ( patterns != null ) && ( patterns.length > 0 ) )
+        {
+            result = new String[patterns.length];
+            for ( int i = 0; i < patterns.length; i++ )
+            {
+                String pattern = patterns[i].trim ();
+
+                // don't normalize the pattern here, we internalize the normalization
+                // just normalize for comparison purposes
+                if ( PathUtils.convertPathForOS ( pattern ).endsWith ( File.separator ) )
+                {
+                    pattern += "**";
+                }
+                result[i] = pattern;
+            }
+        }
+        return result;
+    }
+}