[MSHARED-366] Added reader based api which avoids using files

File based version delegates to reader based version. Testcase added for reader based version,
although most features are tested via the file based version

git-svn-id: https://svn.apache.org/repos/asf/maven/shared/trunk@1631834 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/maven/shared/filtering/BaseFilter.java b/src/main/java/org/apache/maven/shared/filtering/BaseFilter.java
new file mode 100644
index 0000000..9a52394
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/filtering/BaseFilter.java
@@ -0,0 +1,291 @@
+package org.apache.maven.shared.filtering;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.*;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.settings.Settings;
+import org.apache.maven.shared.utils.StringUtils;
+import org.apache.maven.shared.utils.io.FileUtils;
+import org.codehaus.plexus.interpolation.*;
+import org.codehaus.plexus.interpolation.multi.MultiDelimiterStringSearchInterpolator;
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+
+import javax.annotation.Nonnull;
+
+class BaseFilter extends AbstractLogEnabled implements DefaultFilterInfo {
+
+
+	/**
+	 * @see org.apache.maven.shared.filtering.MavenFileFilter#getDefaultFilterWrappers(org.apache.maven.project.MavenProject, java.util.List, boolean, org.apache.maven.execution.MavenSession)
+	 * @deprecated
+	 */
+	public List<FileUtils.FilterWrapper> getDefaultFilterWrappers( final MavenProject mavenProject,
+			List<String> filters,
+			final boolean escapedBackslashesInFilePath,
+			MavenSession mavenSession )
+			throws MavenFilteringException
+	{
+		return getDefaultFilterWrappers( mavenProject, filters, escapedBackslashesInFilePath, mavenSession, null );
+	}
+
+
+	@Nonnull public List<FileUtils.FilterWrapper> getDefaultFilterWrappers( final MavenProject mavenProject, List<String> filters,
+			final boolean escapedBackslashesInFilePath,
+			MavenSession mavenSession,
+			MavenResourcesExecution mavenResourcesExecution )
+			throws MavenFilteringException
+	{
+
+		MavenResourcesExecution mre =
+				mavenResourcesExecution == null ? new MavenResourcesExecution() : mavenResourcesExecution.copyOf();
+
+		mre.setMavenProject( mavenProject );
+		mre.setMavenSession( mavenSession );
+		mre.setFilters( filters );
+		mre.setEscapedBackslashesInFilePath( escapedBackslashesInFilePath );
+
+		return getDefaultFilterWrappers( mre );
+
+	}
+
+	@Nonnull public List<FileUtils.FilterWrapper> getDefaultFilterWrappers( final AbstractMavenFilteringRequest req )
+			throws MavenFilteringException
+	{
+		// backup values
+		boolean supportMultiLineFiltering = req.isSupportMultiLineFiltering();
+
+		// compensate for null parameter value.
+		final AbstractMavenFilteringRequest request = req == null ? new MavenFileFilterRequest() : req;
+
+		request.setSupportMultiLineFiltering( supportMultiLineFiltering );
+
+		// Here we build some properties which will be used to read some properties files
+		// to interpolate the expression ${ } in this properties file
+
+		// Take a copy of filterProperties to ensure that evaluated filterTokens are not propagated
+		// to subsequent filter files. Note: this replicates current behaviour and seems to make sense.
+
+		final Properties baseProps = new Properties();
+
+		// Project properties
+		if ( request.getMavenProject() != null )
+		{
+			baseProps.putAll( request.getMavenProject().getProperties() == null
+					? Collections.emptyMap()
+					: request.getMavenProject().getProperties() );
+		}
+		// TODO this is NPE free but do we consider this as normal
+		// or do we have to throw an MavenFilteringException with mavenSession cannot be null
+		if ( request.getMavenSession() != null )
+		{
+			// execution properties wins
+			baseProps.putAll( request.getMavenSession().getExecutionProperties() );
+		}
+
+		// now we build properties to use for resources interpolation
+
+		final Properties filterProperties = new Properties();
+
+		File basedir = request.getMavenProject() != null ? request.getMavenProject().getBasedir() : new File( "." );
+
+		loadProperties( filterProperties, basedir, request.getFileFilters(), baseProps );
+		if ( filterProperties.size() < 1 )
+		{
+			filterProperties.putAll( baseProps );
+		}
+
+		if ( request.getMavenProject() != null )
+		{
+			if ( request.isInjectProjectBuildFilters() )
+			{
+				@SuppressWarnings( "unchecked" )
+				List<String> buildFilters = new ArrayList<String>( request.getMavenProject().getBuild().getFilters() );
+
+				// JDK-8015656: (coll) unexpected NPE from removeAll
+				if ( request.getFileFilters() != null )
+				{
+					buildFilters.removeAll( request.getFileFilters() );
+				}
+
+				loadProperties( filterProperties, basedir, buildFilters, baseProps );
+			}
+
+			// Project properties
+			filterProperties.putAll( request.getMavenProject().getProperties() == null
+					? Collections.emptyMap()
+					: request.getMavenProject().getProperties() );
+		}
+		if ( request.getMavenSession() != null )
+		{
+			// execution properties wins
+			filterProperties.putAll( request.getMavenSession().getExecutionProperties() );
+		}
+
+		if ( request.getAdditionalProperties() != null )
+		{
+			// additional properties wins
+			filterProperties.putAll( request.getAdditionalProperties() );
+		}
+
+		List<FileUtils.FilterWrapper> defaultFilterWrappers = request == null
+				? new ArrayList<FileUtils.FilterWrapper>( 1 )
+				: new ArrayList<FileUtils.FilterWrapper>( request.getDelimiters().size() + 1 );
+
+		if ( getLogger().isDebugEnabled() )
+		{
+			getLogger().debug( "properties used " + filterProperties );
+		}
+
+		final ValueSource propertiesValueSource = new PropertiesBasedValueSource( filterProperties );
+
+		if ( request != null )
+		{
+			FileUtils.FilterWrapper wrapper =
+					new Wrapper( request.getDelimiters(), request.getMavenProject(), request.getMavenSession(),
+							propertiesValueSource, request.getProjectStartExpressions(), request.getEscapeString(),
+							request.isEscapeWindowsPaths(), request.isSupportMultiLineFiltering() );
+
+			defaultFilterWrappers.add( wrapper );
+		}
+
+		return defaultFilterWrappers;
+	}
+
+	/**
+	 * default visibility only for testing reason !
+	 */
+	void loadProperties( Properties filterProperties, File basedir, List<String> propertiesFilePaths, Properties baseProps )
+			throws MavenFilteringException
+	{
+		if ( propertiesFilePaths != null )
+		{
+			Properties workProperties = new Properties();
+			workProperties.putAll( baseProps );
+
+			for ( String filterFile : propertiesFilePaths )
+			{
+				if ( StringUtils.isEmpty(filterFile) )
+				{
+					// skip empty file name
+					continue;
+				}
+				try
+				{
+					File propFile = FileUtils.resolveFile( basedir, filterFile );
+					Properties properties = PropertyUtils.loadPropertyFile( propFile, workProperties );
+					filterProperties.putAll( properties );
+					workProperties.putAll( properties );
+				}
+				catch ( IOException e )
+				{
+					throw new MavenFilteringException( "Error loading property file '" + filterFile + "'", e );
+				}
+			}
+		}
+	}
+
+	private static final class Wrapper
+			extends FileUtils.FilterWrapper
+	{
+
+		private LinkedHashSet<String> delimiters;
+
+		private MavenProject project;
+
+		private ValueSource propertiesValueSource;
+
+		private List<String> projectStartExpressions;
+
+		private String escapeString;
+
+		private boolean escapeWindowsPaths;
+
+		private final MavenSession mavenSession;
+
+		private boolean supportMultiLineFiltering;
+
+		Wrapper( LinkedHashSet<String> delimiters, MavenProject project, MavenSession mavenSession,
+				ValueSource propertiesValueSource, List<String> projectStartExpressions, String escapeString,
+				boolean escapeWindowsPaths, boolean supportMultiLineFiltering )
+		{
+			super();
+			this.delimiters = delimiters;
+			this.project = project;
+			this.mavenSession = mavenSession;
+			this.propertiesValueSource = propertiesValueSource;
+			this.projectStartExpressions = projectStartExpressions;
+			this.escapeString = escapeString;
+			this.escapeWindowsPaths = escapeWindowsPaths;
+			this.supportMultiLineFiltering = supportMultiLineFiltering;
+		}
+
+		public Reader getReader( Reader reader )
+		{
+			MultiDelimiterStringSearchInterpolator interpolator = new MultiDelimiterStringSearchInterpolator();
+			interpolator.setDelimiterSpecs( delimiters );
+
+			RecursionInterceptor ri = null;
+			if ( projectStartExpressions != null && !projectStartExpressions.isEmpty() )
+			{
+				ri = new PrefixAwareRecursionInterceptor( projectStartExpressions, true );
+			}
+			else
+			{
+				ri = new SimpleRecursionInterceptor();
+			}
+
+			interpolator.addValueSource( propertiesValueSource );
+
+			if ( project != null )
+			{
+				interpolator.addValueSource( new PrefixedObjectValueSource( projectStartExpressions, project, true ) );
+			}
+
+			if ( mavenSession != null )
+			{
+				interpolator.addValueSource( new PrefixedObjectValueSource( "session", mavenSession ) );
+
+				final Settings settings = mavenSession.getSettings();
+				if ( settings != null )
+				{
+					interpolator.addValueSource( new PrefixedObjectValueSource( "settings", settings ) );
+					interpolator.addValueSource(
+							new SingleResponseValueSource( "localRepository", settings.getLocalRepository() ) );
+				}
+			}
+
+			interpolator.setEscapeString( escapeString );
+
+			if ( escapeWindowsPaths )
+			{
+				interpolator.addPostProcessor( new InterpolationPostProcessor()
+				{
+					public Object execute( String expression, Object value )
+					{
+						if ( value instanceof String )
+						{
+							return FilteringUtils.escapeWindowsPath( (String) value );
+						}
+
+						return value;
+					}
+				} );
+			}
+
+			MultiDelimiterInterpolatorFilterReaderLineEnding filterReader =
+					new MultiDelimiterInterpolatorFilterReaderLineEnding( reader, interpolator, supportMultiLineFiltering );
+			filterReader.setRecursionInterceptor( ri );
+			filterReader.setDelimiterSpecs( delimiters );
+
+			filterReader.setInterpolateWithPrefixPattern( false );
+			filterReader.setEscapeString( escapeString );
+
+			return filterReader;
+		}
+
+	}
+}
diff --git a/src/main/java/org/apache/maven/shared/filtering/DefaultFilterInfo.java b/src/main/java/org/apache/maven/shared/filtering/DefaultFilterInfo.java
new file mode 100644
index 0000000..91f92bd
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/filtering/DefaultFilterInfo.java
@@ -0,0 +1,77 @@
+package org.apache.maven.shared.filtering;
+
+
+/*
+ * 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.
+ */
+
+import java.util.List;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.shared.utils.io.FileUtils;
+
+import javax.annotation.Nonnull;
+
+public interface DefaultFilterInfo {
+	/**
+	 * Will return the default FileUtils.FilterWrappers.
+	 * <p/>
+	 * <ul>
+	 * <li>interpolate with token ${} and values from sysProps, project.properties, filters and project filters.</li>
+	 * <li>interpolate with token @ @ and values from sysProps, project.properties, filters and project filters.</li>
+	 * <li>interpolate with token ${} and values from mavenProject interpolation.</li>
+	 * <li>interpolation with token @ @ and values from mavenProject interpolation</li>
+	 * </ul>
+	 * <b>This method is now deprecated and no escape mechanism will be used.</b>
+	 *
+	 * @param mavenProject
+	 * @param filters      {@link java.util.List} of properties file
+	 * @return {@link java.util.List} of FileUtils.FilterWrapper
+	 * @deprecated use {@link #getDefaultFilterWrappers(org.apache.maven.project.MavenProject, java.util.List, boolean, org.apache.maven.execution.MavenSession, org.apache.maven.shared.filtering.MavenResourcesExecution)}
+	 */
+	@Nonnull List<FileUtils.FilterWrapper> getDefaultFilterWrappers(MavenProject mavenProject, List<String> filters,
+			boolean escapedBackslashesInFilePath,
+			MavenSession mavenSession)
+			throws MavenFilteringException;
+
+	/**
+	 * @param mavenProject
+	 * @param filters
+	 * @param escapedBackslashesInFilePath
+	 * @param mavenSession
+	 * @param mavenResourcesExecution
+	 * @return {@link java.util.List} of FileUtils.FilterWrapper
+	 * @throws org.apache.maven.shared.filtering.MavenFilteringException
+	 * @since 1.0-beta-2
+	 */
+	@Nonnull List<FileUtils.FilterWrapper> getDefaultFilterWrappers(MavenProject mavenProject, List<String> filters,
+			boolean escapedBackslashesInFilePath,
+			MavenSession mavenSession,
+			MavenResourcesExecution mavenResourcesExecution)
+			throws MavenFilteringException;
+
+	/**
+	 * @param request
+	 * @return {@link java.util.List} of FileUtils.FilterWrapper
+	 * @throws org.apache.maven.shared.filtering.MavenFilteringException
+	 * @since 1.0-beta-3
+	 */
+	@Nonnull List<FileUtils.FilterWrapper> getDefaultFilterWrappers(AbstractMavenFilteringRequest request)
+			throws MavenFilteringException;
+}
diff --git a/src/main/java/org/apache/maven/shared/filtering/DefaultMavenFileFilter.java b/src/main/java/org/apache/maven/shared/filtering/DefaultMavenFileFilter.java
index f1de523..09cffe0 100644
--- a/src/main/java/org/apache/maven/shared/filtering/DefaultMavenFileFilter.java
+++ b/src/main/java/org/apache/maven/shared/filtering/DefaultMavenFileFilter.java
@@ -19,47 +19,50 @@
  * under the License.
  */
 
-import java.io.File;
-import java.io.IOException;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Properties;
-
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.project.MavenProject;
-import org.apache.maven.settings.Settings;
 import org.apache.maven.shared.utils.StringUtils;
 import org.apache.maven.shared.utils.io.FileUtils;
 import org.apache.maven.shared.utils.io.FileUtils.FilterWrapper;
-import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
-import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
-import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
-import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
-import org.codehaus.plexus.interpolation.RecursionInterceptor;
-import org.codehaus.plexus.interpolation.SimpleRecursionInterceptor;
-import org.codehaus.plexus.interpolation.SingleResponseValueSource;
-import org.codehaus.plexus.interpolation.ValueSource;
-import org.codehaus.plexus.interpolation.multi.MultiDelimiterStringSearchInterpolator;
-import org.codehaus.plexus.logging.AbstractLogEnabled;
+import org.apache.maven.shared.utils.io.IOUtil;
 import org.sonatype.plexus.build.incremental.BuildContext;
 
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.List;
+
 /**
  * @author Olivier Lamy
- *
  * @plexus.component role="org.apache.maven.shared.filtering.MavenFileFilter"
  * role-hint="default"
  */
 public class DefaultMavenFileFilter
-    extends AbstractLogEnabled
+    extends BaseFilter
     implements MavenFileFilter
 {
 
     /**
      * @plexus.requirement
      */
+    private MavenReaderFilter readerFilter;
+
+    /**
+     * @plexus.requirement
+     */
     private BuildContext buildContext;
 
     public void copyFile( File from, File to, boolean filtering, MavenProject mavenProject, List<String> filters,
@@ -109,9 +112,7 @@
                 {
                     getLogger().debug( "filtering " + from.getPath() + " to " + to.getPath() );
                 }
-                FileUtils.FilterWrapper[] wrappers = filterWrappers.toArray(
-                    new FileUtils.FilterWrapper[filterWrappers.size()] );
-                FileUtils.copyFile( from, to, encoding, wrappers );
+                filterFile( from, to, encoding, filterWrappers );
             }
             else
             {
@@ -131,274 +132,66 @@
 
     }
 
-    /**
-     * @see org.apache.maven.shared.filtering.MavenFileFilter#getDefaultFilterWrappers(org.apache.maven.project.MavenProject, java.util.List, boolean, org.apache.maven.execution.MavenSession)
-     * @deprecated
-     */
-    public List<FileUtils.FilterWrapper> getDefaultFilterWrappers( final MavenProject mavenProject,
-                                                                   List<String> filters,
-                                                                   final boolean escapedBackslashesInFilePath,
-                                                                   MavenSession mavenSession )
-        throws MavenFilteringException
+    private void filterFile( @Nonnull File from, @Nonnull File to, @Nullable String encoding,
+                             @Nullable List<FilterWrapper> wrappers )
+        throws IOException, MavenFilteringException
     {
-        return getDefaultFilterWrappers( mavenProject, filters, escapedBackslashesInFilePath, mavenSession, null );
-    }
-
-
-    public List<FileUtils.FilterWrapper> getDefaultFilterWrappers( final MavenProject mavenProject, List<String> filters,
-                                                                   final boolean escapedBackslashesInFilePath,
-                                                                   MavenSession mavenSession,
-                                                                   MavenResourcesExecution mavenResourcesExecution )
-        throws MavenFilteringException
-    {
-
-        MavenResourcesExecution mre =
-            mavenResourcesExecution == null ? new MavenResourcesExecution() : mavenResourcesExecution.copyOf();
-
-        mre.setMavenProject( mavenProject );
-        mre.setMavenSession( mavenSession );
-        mre.setFilters( filters );
-        mre.setEscapedBackslashesInFilePath( escapedBackslashesInFilePath );
-
-        return getDefaultFilterWrappers( mre );
-
-    }
-
-    public List<FileUtils.FilterWrapper> getDefaultFilterWrappers( final AbstractMavenFilteringRequest req )
-        throws MavenFilteringException
-    {
-        // backup values
-        boolean supportMultiLineFiltering = req.isSupportMultiLineFiltering();
-
-        // compensate for null parameter value.
-        final AbstractMavenFilteringRequest request = req == null ? new MavenFileFilterRequest() : req;
-
-        request.setSupportMultiLineFiltering( supportMultiLineFiltering );
-
-        // Here we build some properties which will be used to read some properties files
-        // to interpolate the expression ${ } in this properties file
-
-        // Take a copy of filterProperties to ensure that evaluated filterTokens are not propagated
-        // to subsequent filter files. Note: this replicates current behaviour and seems to make sense.
-
-        final Properties baseProps = new Properties();
-
-        // Project properties
-        if ( request.getMavenProject() != null )
+        if ( wrappers != null && wrappers.size() > 0 )
         {
-            baseProps.putAll( request.getMavenProject().getProperties() == null
-                                  ? Collections.emptyMap()
-                                  : request.getMavenProject().getProperties() );
-        }
-        // TODO this is NPE free but do we consider this as normal
-        // or do we have to throw an MavenFilteringException with mavenSession cannot be null
-        if ( request.getMavenSession() != null )
-        {
-            // execution properties wins
-            baseProps.putAll( request.getMavenSession().getExecutionProperties() );
-        }
-
-        // now we build properties to use for resources interpolation
-
-        final Properties filterProperties = new Properties();
-
-        File basedir = request.getMavenProject() != null ? request.getMavenProject().getBasedir() : new File( "." ); 
-
-        loadProperties( filterProperties, basedir, request.getFileFilters(), baseProps );
-        if ( filterProperties.size() < 1 )
-        {
-            filterProperties.putAll( baseProps );
-        }
-
-        if ( request.getMavenProject() != null )
-        {
-            if ( request.isInjectProjectBuildFilters() )
+            Reader fileReader = null;
+            Writer fileWriter = null;
+            try
             {
-                @SuppressWarnings( "unchecked" )
-                List<String> buildFilters = new ArrayList<String>( request.getMavenProject().getBuild().getFilters() );
+                fileReader = getFileReader( encoding, from );
+                fileWriter = getFileWriter( encoding, to );
+                Reader src = readerFilter.filter( fileReader, true, wrappers );
 
-                // JDK-8015656: (coll) unexpected NPE from removeAll 
-                if ( request.getFileFilters() != null )
-                {
-                    buildFilters.removeAll( request.getFileFilters() );
-                }
-
-                loadProperties( filterProperties, basedir, buildFilters, baseProps );
+                IOUtil.copy( src, fileWriter );
             }
-
-            // Project properties
-            filterProperties.putAll( request.getMavenProject().getProperties() == null
-                                         ? Collections.emptyMap()
-                                         : request.getMavenProject().getProperties() );
-        }
-        if ( request.getMavenSession() != null )
-        {
-            // execution properties wins
-            filterProperties.putAll( request.getMavenSession().getExecutionProperties() );
-        }
-
-        if ( request.getAdditionalProperties() != null )
-        {
-            // additional properties wins
-            filterProperties.putAll( request.getAdditionalProperties() );
-        }
-
-        List<FileUtils.FilterWrapper> defaultFilterWrappers = request == null
-            ? new ArrayList<FileUtils.FilterWrapper>( 1 )
-            : new ArrayList<FileUtils.FilterWrapper>( request.getDelimiters().size() + 1 );
-
-        if ( getLogger().isDebugEnabled() )
-        {
-            getLogger().debug( "properties used " + filterProperties );
-        }
-
-        final ValueSource propertiesValueSource = new PropertiesBasedValueSource( filterProperties );
-
-        if ( request != null )
-        {
-            FileUtils.FilterWrapper wrapper =
-                new Wrapper( request.getDelimiters(), request.getMavenProject(), request.getMavenSession(),
-                             propertiesValueSource, request.getProjectStartExpressions(), request.getEscapeString(),
-                             request.isEscapeWindowsPaths(), request.isSupportMultiLineFiltering() );
-
-            defaultFilterWrappers.add( wrapper );
-        }
-
-        return defaultFilterWrappers;
-    }
-
-    /**
-     * default visibility only for testing reason !
-     */
-    void loadProperties( Properties filterProperties, File basedir, List<String> propertiesFilePaths, Properties baseProps )
-        throws MavenFilteringException
-    {
-        if ( propertiesFilePaths != null )
-        {
-            Properties workProperties = new Properties();
-            workProperties.putAll( baseProps );
-
-            for ( String filterFile : propertiesFilePaths )
+            finally
             {
-                if ( StringUtils.isEmpty( filterFile ) )
-                {
-                    // skip empty file name
-                    continue;
-                }
-                try
-                {
-                    File propFile = FileUtils.resolveFile( basedir, filterFile );
-                    Properties properties = PropertyUtils.loadPropertyFile( propFile, workProperties );
-                    filterProperties.putAll( properties );
-                    workProperties.putAll( properties );
-                }
-                catch ( IOException e )
-                {
-                    throw new MavenFilteringException( "Error loading property file '" + filterFile + "'", e );
-                }
+                IOUtil.close( fileReader );
+                IOUtil.close( fileWriter );
+            }
+        }
+        else
+        {
+            if ( to.lastModified() < from.lastModified()  )
+            {
+                FileUtils.copyFile( from, to );
             }
         }
     }
 
-    private static final class Wrapper
-        extends FileUtils.FilterWrapper
+    private Writer getFileWriter( String encoding, File to )
+        throws IOException
     {
-
-        private LinkedHashSet<String> delimiters;
-
-        private MavenProject project;
-
-        private ValueSource propertiesValueSource;
-
-        private List<String> projectStartExpressions;
-
-        private String escapeString;
-
-        private boolean escapeWindowsPaths;
-
-        private final MavenSession mavenSession;
-
-        private boolean supportMultiLineFiltering;
-
-        Wrapper( LinkedHashSet<String> delimiters, MavenProject project, MavenSession mavenSession,
-                 ValueSource propertiesValueSource, List<String> projectStartExpressions, String escapeString,
-                 boolean escapeWindowsPaths, boolean supportMultiLineFiltering )
+        if ( StringUtils.isEmpty( encoding ) )
         {
-            super();
-            this.delimiters = delimiters;
-            this.project = project;
-            this.mavenSession = mavenSession;
-            this.propertiesValueSource = propertiesValueSource;
-            this.projectStartExpressions = projectStartExpressions;
-            this.escapeString = escapeString;
-            this.escapeWindowsPaths = escapeWindowsPaths;
-            this.supportMultiLineFiltering = supportMultiLineFiltering;
+            return new FileWriter( to );
         }
-
-        public Reader getReader( Reader reader )
+        else
         {
-            MultiDelimiterStringSearchInterpolator interpolator = new MultiDelimiterStringSearchInterpolator();
-            interpolator.setDelimiterSpecs( delimiters );
+            FileOutputStream outstream = new FileOutputStream( to );
 
-            RecursionInterceptor ri = null;
-            if ( projectStartExpressions != null && !projectStartExpressions.isEmpty() )
-            {
-                ri = new PrefixAwareRecursionInterceptor( projectStartExpressions, true );
-            }
-            else
-            {
-                ri = new SimpleRecursionInterceptor();
-            }
-
-            interpolator.addValueSource( propertiesValueSource );
-
-            if ( project != null )
-            {
-                interpolator.addValueSource( new PrefixedObjectValueSource( projectStartExpressions, project, true ) );
-            }
-
-            if ( mavenSession != null )
-            {
-                interpolator.addValueSource( new PrefixedObjectValueSource( "session", mavenSession ) );
-
-                final Settings settings = mavenSession.getSettings();
-                if ( settings != null )
-                {
-                    interpolator.addValueSource( new PrefixedObjectValueSource( "settings", settings ) );
-                    interpolator.addValueSource(
-                        new SingleResponseValueSource( "localRepository", settings.getLocalRepository() ) );
-                }
-            }
-
-            interpolator.setEscapeString( escapeString );
-
-            if ( escapeWindowsPaths )
-            {
-                interpolator.addPostProcessor( new InterpolationPostProcessor()
-                {
-                    public Object execute( String expression, Object value )
-                    {
-                        if ( value instanceof String )
-                        {
-                            return FilteringUtils.escapeWindowsPath( (String) value );
-                        }
-
-                        return value;
-                    }
-                } );
-            }
-
-            MultiDelimiterInterpolatorFilterReaderLineEnding filterReader =
-                new MultiDelimiterInterpolatorFilterReaderLineEnding( reader, interpolator, supportMultiLineFiltering );
-            filterReader.setRecursionInterceptor( ri );
-            filterReader.setDelimiterSpecs( delimiters );
-
-            filterReader.setInterpolateWithPrefixPattern( false );
-            filterReader.setEscapeString( escapeString );
-
-            return filterReader;
+            return new OutputStreamWriter( outstream, encoding );
         }
-
     }
 
+    private Reader getFileReader( String encoding, File from )
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        // buffer so it isn't reading a byte at a time!
+        if ( StringUtils.isEmpty( encoding ) )
+        {
+            return new BufferedReader( new FileReader( from ) );
+        }
+        else
+        {
+            FileInputStream instream = new FileInputStream( from );
+            return new BufferedReader( new InputStreamReader( instream, encoding ) );
+        }
+    }
+
+
 }
diff --git a/src/main/java/org/apache/maven/shared/filtering/DefaultMavenReaderFilter.java b/src/main/java/org/apache/maven/shared/filtering/DefaultMavenReaderFilter.java
new file mode 100644
index 0000000..5f02438
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/filtering/DefaultMavenReaderFilter.java
@@ -0,0 +1,83 @@
+package org.apache.maven.shared.filtering;
+
+/*
+ * 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.
+ */
+
+import edu.emory.mathcs.backport.java.util.Collections;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.shared.utils.io.FileUtils.FilterWrapper;
+
+import javax.annotation.Nonnull;
+import java.io.Reader;
+import java.util.List;
+
+/**
+ * @author Kristian Rosenvold
+ * @plexus.component role="org.apache.maven.shared.filtering.MavenReaderFilter"
+ * role-hint="default"
+ */
+public class DefaultMavenReaderFilter
+    extends BaseFilter
+    implements MavenReaderFilter
+{
+    @Nonnull
+    public Reader filter( @Nonnull Reader from, boolean filtering, MavenProject mavenProject, List<String> filters,
+                          boolean escapedBackslashesInFilePath, MavenSession mavenSession )
+        throws MavenFilteringException
+    {
+        MavenResourcesExecution mre = new MavenResourcesExecution();
+        mre.setMavenProject( mavenProject );
+        mre.setFileFilters( filters );
+        mre.setEscapeWindowsPaths( escapedBackslashesInFilePath );
+        mre.setMavenSession( mavenSession );
+        mre.setInjectProjectBuildFilters( true );
+
+        List<FilterWrapper> filterWrappers = getDefaultFilterWrappers( mre );
+        return filter( from, filtering, filterWrappers );
+    }
+
+
+    @Nonnull public Reader filter( @Nonnull MavenReaderFilterRequest mavenFileFilterRequest )
+        throws MavenFilteringException
+    {
+        List<FilterWrapper> filterWrappers = getDefaultFilterWrappers( mavenFileFilterRequest );
+        return filter( mavenFileFilterRequest.getFrom(), mavenFileFilterRequest.isFiltering(), filterWrappers );
+    }
+
+
+    @SuppressWarnings( "unchecked" )
+    public @Nonnull Reader filter( @Nonnull Reader from, boolean filtering, @Nonnull List<FilterWrapper> filterWrappers )
+    {
+        return filterWrap( from, filtering ? filterWrappers : Collections.<FilterWrapper>emptyList() );
+    }
+
+
+    private static @Nonnull Reader filterWrap( @Nonnull Reader from, @Nonnull Iterable<FilterWrapper> wrappers )
+    {
+        Reader reader = from;
+        for ( FilterWrapper wrapper : wrappers )
+        {
+            reader = wrapper.getReader( reader );
+        }
+        return reader;
+    }
+
+
+}
diff --git a/src/main/java/org/apache/maven/shared/filtering/MavenFileFilter.java b/src/main/java/org/apache/maven/shared/filtering/MavenFileFilter.java
index dbc7bdd..b383649 100644
--- a/src/main/java/org/apache/maven/shared/filtering/MavenFileFilter.java
+++ b/src/main/java/org/apache/maven/shared/filtering/MavenFileFilter.java
@@ -30,7 +30,7 @@
  * @author Olivier Lamy
  *
  */
-public interface MavenFileFilter
+public interface MavenFileFilter extends DefaultFilterInfo
 {
 
     /**
@@ -81,51 +81,4 @@
     void copyFile( File from, final File to, boolean filtering, List<FileUtils.FilterWrapper> filterWrappers,
                    String encoding, boolean overwrite )
         throws MavenFilteringException;
-
-    /**
-     * Will return the default FileUtils.FilterWrappers.
-     * <p/>
-     * <ul>
-     * <li>interpolate with token ${} and values from sysProps, project.properties, filters and project filters.</li>
-     * <li>interpolate with token @ @ and values from sysProps, project.properties, filters and project filters.</li>
-     * <li>interpolate with token ${} and values from mavenProject interpolation.</li>
-     * <li>interpolation with token @ @ and values from mavenProject interpolation</li>
-     * </ul>
-     * <b>This method is now deprecated and no escape mechanism will be used.</b>
-     *
-     * @param mavenProject
-     * @param filters      {@link List} of properties file
-     * @return {@link List} of FileUtils.FilterWrapper
-     * @deprecated use {@link #getDefaultFilterWrappers(MavenProject, List, boolean, MavenSession, MavenResourcesExecution)}
-     */
-    List<FileUtils.FilterWrapper> getDefaultFilterWrappers( MavenProject mavenProject, List<String> filters,
-                                                            boolean escapedBackslashesInFilePath,
-                                                            MavenSession mavenSession )
-        throws MavenFilteringException;
-
-    /**
-     * @param mavenProject
-     * @param filters
-     * @param escapedBackslashesInFilePath
-     * @param mavenSession
-     * @param mavenResourcesExecution
-     * @return {@link List} of FileUtils.FilterWrapper
-     * @throws MavenFilteringException
-     * @since 1.0-beta-2
-     */
-    List<FileUtils.FilterWrapper> getDefaultFilterWrappers( MavenProject mavenProject, List<String> filters,
-                                                            boolean escapedBackslashesInFilePath,
-                                                            MavenSession mavenSession,
-                                                            MavenResourcesExecution mavenResourcesExecution )
-        throws MavenFilteringException;
-
-    /**
-     * @param request
-     * @return {@link List} of FileUtils.FilterWrapper
-     * @throws MavenFilteringException
-     * @since 1.0-beta-3
-     */
-    List<FileUtils.FilterWrapper> getDefaultFilterWrappers( AbstractMavenFilteringRequest request )
-        throws MavenFilteringException;
-
 }
diff --git a/src/main/java/org/apache/maven/shared/filtering/MavenReaderFilter.java b/src/main/java/org/apache/maven/shared/filtering/MavenReaderFilter.java
new file mode 100644
index 0000000..84bf95e
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/filtering/MavenReaderFilter.java
@@ -0,0 +1,75 @@
+package org.apache.maven.shared.filtering;
+
+/*
+ * 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.
+ */
+
+import java.io.Reader;
+import java.util.List;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.shared.utils.io.FileUtils;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * @author Olivier Lamy
+ * @author Kristian Rosenvold
+ * @since 1.3
+ */
+public interface MavenReaderFilter
+    extends DefaultFilterInfo
+{
+    /**
+     * Provides a new reader that applies filtering using defaultFilterWrappers.
+     *
+     * @param from  the source reader
+     * @param filtering    enable or not filering
+     * @param mavenProject the mavenproject
+     * @param filters      {@link java.util.List} of String which are path to a Property file
+     * @return an input stream that applies the filter
+     * @throws org.apache.maven.shared.filtering.MavenFilteringException
+     * @see #getDefaultFilterWrappers(org.apache.maven.project.MavenProject, java.util.List, boolean, org.apache.maven.execution.MavenSession)
+     */
+    @Nonnull Reader filter( @Nonnull Reader from, boolean filtering, @Nullable MavenProject mavenProject, List<String> filters,
+                   boolean escapedBackslashesInFilePath, MavenSession mavenSession )
+        throws MavenFilteringException;
+
+    /**
+     * Provides a new reader that applies filtering using defaultFilterWrappers.
+     *
+     * @param mavenFileFilterRequest The filter request
+     * @throws org.apache.maven.shared.filtering.MavenFilteringException
+     * @return an input stream that applies the filter
+     * @since 1.0-beta-3
+     */
+    @Nonnull Reader filter( @Nonnull MavenReaderFilterRequest mavenFileFilterRequest )
+        throws MavenFilteringException;
+
+    /**
+     * Provides a new reader that applies filtering using defaultFilterWrappers.
+     *
+     * @param from  the source reader
+     * @param filtering true to apply filtering
+     * @param filterWrappers {@link java.util.List} of FileUtils.FilterWrapper
+     * @return an input stream that applies the filter
+     */
+    @Nonnull Reader filter( @Nonnull Reader from, boolean filtering, @Nonnull List<FileUtils.FilterWrapper> filterWrappers );
+}
diff --git a/src/main/java/org/apache/maven/shared/filtering/MavenReaderFilterRequest.java b/src/main/java/org/apache/maven/shared/filtering/MavenReaderFilterRequest.java
new file mode 100644
index 0000000..9c64a80
--- /dev/null
+++ b/src/main/java/org/apache/maven/shared/filtering/MavenReaderFilterRequest.java
@@ -0,0 +1,81 @@
+package org.apache.maven.shared.filtering;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+
+/**
+ * @author Olivier Lamy
+ * @author Kristian Rosenvold
+ * @since 1.0-beta-3
+ */
+public class MavenReaderFilterRequest
+    extends AbstractMavenFilteringRequest
+{
+
+    private Reader from;
+
+    private boolean filtering;
+
+    public MavenReaderFilterRequest()
+    {
+        // nothing
+    }
+
+    public MavenReaderFilterRequest( Reader from, boolean filtering, MavenProject mavenProject, List<String> filters,
+                                     boolean escapedBackslashesInFilePath, String encoding, MavenSession mavenSession,
+                                     Properties additionalProperties )
+    {
+        super( mavenProject, filters, encoding, mavenSession );
+        this.from = from;
+        this.filtering = filtering;
+        setAdditionalProperties( additionalProperties );
+        setEscapeWindowsPaths( escapedBackslashesInFilePath );
+    }
+
+
+    public Reader getFrom()
+    {
+        return from;
+    }
+
+    public void setFrom( Reader from )
+    {
+        this.from = from;
+    }
+
+    public boolean isFiltering()
+    {
+        return filtering;
+    }
+
+    public void setFiltering( boolean filtering )
+    {
+        this.filtering = filtering;
+    }
+
+}
diff --git a/src/test/java/org/apache/maven/shared/filtering/DefaultMavenReaderFilterTest.java b/src/test/java/org/apache/maven/shared/filtering/DefaultMavenReaderFilterTest.java
new file mode 100644
index 0000000..9f85e42
--- /dev/null
+++ b/src/test/java/org/apache/maven/shared/filtering/DefaultMavenReaderFilterTest.java
@@ -0,0 +1,34 @@
+package org.apache.maven.shared.filtering;
+
+import org.apache.maven.shared.utils.io.IOUtil;
+import org.codehaus.plexus.PlexusTestCase;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.Properties;
+
+/**
+ * @author Kristian Rosenvold
+ *
+ */
+public class DefaultMavenReaderFilterTest
+    extends PlexusTestCase
+{
+    public void testJustDoSomeFiltering() throws Exception
+    {
+        assertNotNull(DefaultMavenReaderFilter.class);
+        MavenReaderFilter readerFilter = (MavenReaderFilter) lookup( MavenReaderFilter.class.getName(), "default" );
+
+        StringReader src = new StringReader( "toto@titi.com ${foo}" );
+        MavenReaderFilterRequest req = new MavenReaderFilterRequest();
+        Properties additionalProperties = new Properties();
+        additionalProperties.setProperty( "foo", "bar" );
+        req.setFrom( src );
+        req.setFiltering( true );
+        req.setAdditionalProperties( additionalProperties );
+
+        final Reader filter = readerFilter.filter( req );
+
+        assertEquals( "toto@titi.com bar", IOUtil.toString( filter ) );
+    }
+}