Bug 412997 - use correct resource encoding when reading .java files

Change-Id: I0eb6a0df61cd770c8f473915ccc311ddb1f2f4f4
diff --git a/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/model/tests/BadClassfileTests.java b/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/model/tests/BadClassfileTests.java
index e1bc01b..69bd336 100644
--- a/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/model/tests/BadClassfileTests.java
+++ b/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/model/tests/BadClassfileTests.java
@@ -22,6 +22,7 @@
 import org.eclipse.osgi.service.resolver.ResolverError;
 import org.eclipse.pde.api.tools.internal.ApiDescription;
 import org.eclipse.pde.api.tools.internal.CompilationUnit;
+import org.eclipse.pde.api.tools.internal.IApiCoreConstants;
 import org.eclipse.pde.api.tools.internal.builder.Reference;
 import org.eclipse.pde.api.tools.internal.model.ApiBaseline;
 import org.eclipse.pde.api.tools.internal.model.Component;
@@ -156,7 +157,7 @@
 	 */
 	public void testTagScanner() throws Exception {
 		writePreamble("testTagScanner()");
-		CompilationUnit unit = new CompilationUnit(TestSuiteHelper.getPluginDirectoryPath().append("test-classes").append("bad").append("nobytecodes.java").toOSString());
+		CompilationUnit unit = new CompilationUnit(TestSuiteHelper.getPluginDirectoryPath().append("test-classes").append("bad").append("nobytecodes.java").toOSString(), IApiCoreConstants.UTF_8);
 		TagScanner scanner = TagScanner.newScanner();
 		try {
 			scanner.scan(unit, new ApiDescription("test"), this.container, null, null);
diff --git a/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/model/tests/TagScannerTests.java b/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/model/tests/TagScannerTests.java
index 3da6946..1c16281 100644
--- a/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/model/tests/TagScannerTests.java
+++ b/apitools/org.eclipse.pde.api.tools.tests/src/org/eclipse/pde/api/tools/model/tests/TagScannerTests.java
@@ -20,6 +20,7 @@
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.pde.api.tools.internal.ApiDescription;
 import org.eclipse.pde.api.tools.internal.CompilationUnit;
+import org.eclipse.pde.api.tools.internal.IApiCoreConstants;
 import org.eclipse.pde.api.tools.internal.model.ArchiveApiTypeContainer;
 import org.eclipse.pde.api.tools.internal.model.DirectoryApiTypeContainer;
 import org.eclipse.pde.api.tools.internal.provisional.Factory;
@@ -74,7 +75,7 @@
 	 */
 	private CompilationUnit getCompilationUnit(String name) {
 		Path path = (Path)SRC_LOC.append(name);
-		return new CompilationUnit(path.toOSString());
+		return new CompilationUnit(path.toOSString(), IApiCoreConstants.UTF_8);
 	}
 	
 	/**
diff --git a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/CompilationUnit.java b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/CompilationUnit.java
index 7eb4996..5052f7e 100644
--- a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/CompilationUnit.java
+++ b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/CompilationUnit.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2009 IBM Corporation and others.
+ * Copyright (c) 2007, 2013 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -16,6 +16,9 @@
 import java.io.InputStream;
 
 import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.jdt.core.ICompilationUnit;
 
@@ -30,25 +33,77 @@
 	private String name = null;
 	private String filepath = null;
 	private ICompilationUnit unit = null;
+	/**
+	 * The encoding to use when reading the compilation units' contents
+	 * 
+	 * @since 1.0.600
+	 */
+	private String encoding = null;
 	
 	/**
 	 * The full path to the file
 	 * Constructor
 	 * @param filepath the absolute path to the file. If the path points to a file that does
 	 * not exist an {@link IllegalArgumentException} is thrown
+	 * @param encoding the file encoding for the backing source
 	 */
-	public CompilationUnit(String filepath) {
+	public CompilationUnit(String filepath, String encoding) {
 		File file = new File(filepath);
 		if(!file.exists()) {
 			throw new IllegalArgumentException("The specified path is not an existing file"); //$NON-NLS-1$
 		}
 		this.filepath = filepath;
 		name = file.getName();
+		this.encoding = resolveEncoding(encoding);
 	}
 	
+	/**
+	 * Constructor for use within the workspace
+	 * 
+	 * @param compilationUnit the {@link ICompilationUnit} backing this {@link CompilationUnit}
+	 */
 	public CompilationUnit(ICompilationUnit compilationUnit) {
 		unit = compilationUnit;
 		name = compilationUnit.getElementName();
+		this.encoding = resolveEncoding(null);
+	}
+	
+	/**
+	 * Resolves the file encoding to use given the base.
+	 * <br><br>
+	 * If there is no base encoding we check if there is a backing {@link ICompilationUnit}, and if so we 
+	 * try to use its direct resource encoding. Failing that we try to get it's projects' encoding. Failing that 
+	 * we try to use the workspace encoding.
+	 * <br><br>
+	 * If there is no backing {@link ICompilationUnit}, for example when created from one of the Ant tasks,
+	 * we simply use the system encoding if the encoding has not already been set.
+	 * @param base
+	 * @return the encoding to use for this {@link CompilationUnit}
+	 * @since 1.0.600
+	 */
+	String resolveEncoding(String base) {
+		if(base != null) {
+			return base;
+		}
+		if(unit != null) {
+			IResource resource = unit.getResource();
+			if(resource != null && resource.getType() == IResource.FILE) {
+				try {
+					return ((IFile)resource).getCharset();
+				} catch (CoreException e) {
+					try {
+						IProject p = resource.getProject();
+						if(p != null) {
+							return p.getDefaultCharset();
+						}
+					} catch (CoreException ce) {
+						//fall through, either the project was null or we had an exception
+					}
+				}
+			}
+			return ResourcesPlugin.getEncoding();
+		}
+		return System.getProperty("file.encoding"); //$NON-NLS-1$
 	}
 	
 	/**
@@ -69,13 +124,23 @@
 			try {
 				return ((IFile)(unit.getCorrespondingResource())).getContents();
 			} catch (CoreException e) {
-				// TODO: should throw CoreException
 				throw new FileNotFoundException(e.getStatus().getMessage());
 			}
 		}
 		return new FileInputStream(new File(filepath));
 	}
 	
+	/**
+	 * Returns the encoding for this compilation unit.
+	 * 
+	 * @return the encoding to use
+	 * @throws CoreException
+	 * @since 1.0.600
+	 */
+	public String getEncoding() throws CoreException {
+		return this.encoding;
+	}
+	
 	/* (non-Javadoc)
 	 * @see java.lang.Object#toString()
 	 */
diff --git a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/provisional/scanner/TagScanner.java b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/provisional/scanner/TagScanner.java
index e627173..11b7778 100644
--- a/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/provisional/scanner/TagScanner.java
+++ b/apitools/org.eclipse.pde.api.tools/src/org/eclipse/pde/api/tools/internal/provisional/scanner/TagScanner.java
@@ -461,7 +461,7 @@
 		InputStream inputStream = null;
 		try {
 			inputStream = source.getInputStream();
-			parser.setSource(Util.getInputStreamAsCharArray(inputStream, -1, System.getProperty("file.encoding"))); //$NON-NLS-1$
+			parser.setSource(Util.getInputStreamAsCharArray(inputStream, -1, source.getEncoding()));
 		} catch (FileNotFoundException e) {
 			throw new CoreException(new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID,
 					MessageFormat.format("Compilation unit source not found: {0}", new String[]{source.getName()}), e)); //$NON-NLS-1$
diff --git a/apitools/org.eclipse.pde.api.tools/src_ant/org/eclipse/pde/api/tools/internal/tasks/ApiFileGenerationTask.java b/apitools/org.eclipse.pde.api.tools/src_ant/org/eclipse/pde/api/tools/internal/tasks/ApiFileGenerationTask.java
index 9bdbe38..0f6a968 100644
--- a/apitools/org.eclipse.pde.api.tools/src_ant/org/eclipse/pde/api/tools/internal/tasks/ApiFileGenerationTask.java
+++ b/apitools/org.eclipse.pde.api.tools/src_ant/org/eclipse/pde/api/tools/internal/tasks/ApiFileGenerationTask.java
@@ -110,6 +110,11 @@
 	String manifests;
 	String sourceLocations;
 	boolean allowNonApiProject = false;
+	/**
+	 * The encoding to read the source files with
+	 * @since 1.0.600
+	 */
+	String encoding;
 	Set apiPackages = new HashSet(0);
 
 	/**
@@ -165,7 +170,15 @@
 	public void setAllowNonApiProject(String allow) {
 		this.allowNonApiProject = Boolean.valueOf(allow).booleanValue();
 	}
-	
+	/**
+	 * Sets the encoding the task should use when reading text streams
+	 * 
+	 * @param encoding
+	 * @since 1.0.600
+	 */
+	public void setEncoding(String encoding) {
+		this.encoding = encoding;
+	}
 	/**
 	 * Set the debug value.
 	 * <p>The possible values are: <code>true</code>, <code>false</code></p>
@@ -179,7 +192,7 @@
 	/**
 	 * Set the extra manifest files' locations.
 	 * 
-	 * <p>This is a list of extra MANIFEST.MF files' locations that can be set to provide more api
+	 * <p>This is a list of extra MANIFEST.MF files' locations that can be set to provide more API
 	 * packages to scan. They are separated by the platform path separator. Each entry must exist.</p>
 	 * <p>If the path is not absolute, it will be resolved relative to the current working directory.</p>
 	 * <p>Jar files can be specified instead of MANIFEST.MF file. If a jar file is specified, its MANIFEST.MF file
@@ -202,6 +215,7 @@
 	public void setExtraSourceLocations(String sourceLocations) {
 		this.sourceLocations = sourceLocations;
 	}
+	
 	/**
 	 * Execute the ant task
 	 */
@@ -227,6 +241,7 @@
 		}
 		if (this.debug) {
 			System.out.println("Project name : " + this.projectName); //$NON-NLS-1$
+			System.out.println("Encoding: " + this.encoding); //$NON-NLS-1$
 			System.out.println("Project location : " + this.projectLocation); //$NON-NLS-1$
 			System.out.println("Binary locations : " + this.binaryLocations); //$NON-NLS-1$
 			System.out.println("Target folder : " + this.targetFolder); //$NON-NLS-1$
@@ -246,7 +261,7 @@
 			throw new BuildException(
 					NLS.bind(Messages.api_generation_projectLocationNotADirectory, this.projectLocation));
 		}
-		// check if the project contains the api tools nature
+		// check if the project contains the API tools nature
 		File dotProjectFile = new File(root, ".project"); //$NON-NLS-1$
 		
 		if(!this.allowNonApiProject && !isAPIToolsNature(dotProjectFile)) {
@@ -398,7 +413,7 @@
 			options.put(JavaCore.COMPILER_COMPLIANCE, resolveCompliance(manifestMap));
 			CompilationUnit unit = null;
 			for (int i = 0, max = allFiles.length; i < max; i++) {
-				unit = new CompilationUnit(allFiles[i].getAbsolutePath());
+				unit = new CompilationUnit(allFiles[i].getAbsolutePath(), this.encoding);
 				if (this.debug) {
 					System.out.println("Unit name[" + i + "] : " + unit.getName()); //$NON-NLS-1$ //$NON-NLS-2$
 				}
@@ -445,9 +460,9 @@
 	}
 	
 	/**
-	 * Collects the names of the packages that are API for the bundle the api description is being created for
+	 * Collects the names of the packages that are API for the bundle the API description is being created for
 	 * @param manifestmap
-	 * @return the names of the packages that are API for the bundle the api description is being created for
+	 * @return the names of the packages that are API for the bundle the API description is being created for
 	 * @throws BundleException if parsing the manifest map to get API package names fail for some reason
 	 */
 	private Set/*<String>*/ collectApiPackageNames(Map manifestmap) throws BundleException {