/*
* Copyright (c) 2010-2012 Research In Motion Limited. All rights reserved.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License, Version 1.0,
* which accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*
*/
package net.rim.ejde.internal.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.Vector;
import java.util.regex.Pattern;
import net.rim.ejde.internal.builders.ResourceBuilder;
import net.rim.ejde.internal.core.ContextManager;
import net.rim.ejde.internal.core.IConstants;
import net.rim.ejde.internal.imports.LegacyImportHelper;
import net.rim.ejde.internal.model.BasicBlackBerryProperties.PreprocessorTag;
import net.rim.ejde.internal.model.BlackBerryProjectCoreNature;
import net.rim.ejde.internal.model.BlackBerryProjectPreprocessingNature;
import net.rim.ejde.internal.model.IModelConstants.IArtifacts;
import net.rim.ide.OSUtils;
import net.rim.ide.Project;
import net.rim.ide.WorkspaceFile;
import net.rim.ide.core.Util;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.core.UserLibrary;
import org.eclipse.jdt.ui.PreferenceConstants;
public class ImportUtils {
static private final Logger _log = Logger.getLogger( ImportUtils.class );
static private final int HAS_RES_FILE = 1;
static private final int HAS_LOCALE_FILE = 2;
static public final int PROJECT_SRC_FOLDE_INDEX = 0;
static public final int PROJECT_RES_FOLDE_INDEX = 1;
static public final int PROJECT_LOCALE_FOLDE_INDEX = 2;
static private final Pattern validPPTagPattern = Pattern.compile( IConstants.PP_VALIDATION_REG_EX );
static public String[] POTENTIAL_SOURCE_FOLDERS;
static {
POTENTIAL_SOURCE_FOLDERS = new String[ 3 ];
String folderName = ImportUtils.getImportPref( LegacyImportHelper.PROJECT_SRC_FOLDER_NAME_KEY );
if( StringUtils.isBlank( folderName ) ) {
POTENTIAL_SOURCE_FOLDERS[ PROJECT_SRC_FOLDE_INDEX ] = "src";
} else {
POTENTIAL_SOURCE_FOLDERS[ PROJECT_SRC_FOLDE_INDEX ] = folderName;
}
folderName = ImportUtils.getImportPref( LegacyImportHelper.PROJECT_RES_FOLDER_NAME_KEY );
if( StringUtils.isBlank( folderName ) ) {
POTENTIAL_SOURCE_FOLDERS[ PROJECT_RES_FOLDE_INDEX ] = "res";
} else {
POTENTIAL_SOURCE_FOLDERS[ PROJECT_RES_FOLDE_INDEX ] = folderName;
}
folderName = ImportUtils.getImportPref( LegacyImportHelper.PROJECT_IMPORT_LOCALE_FOLDER_NAME_KEY );
if( StringUtils.isBlank( folderName ) ) {
POTENTIAL_SOURCE_FOLDERS[ PROJECT_LOCALE_FOLDE_INDEX ] = "src";
} else {
POTENTIAL_SOURCE_FOLDERS[ PROJECT_LOCALE_FOLDE_INDEX ] = folderName;
}
}
/**
* Creates a IProject instance with its natures and builders initialized.
*
* @param name
* @return An IProject instance or <code>null</null> if any error occurred.
*/
static public IProject createEclipseProjectHandler( String name, IPath location ) {
if( StringUtils.isEmpty( name ) )
throw new IllegalArgumentException( "Can't create Eclipse project for undefined name!" );
if( location != null ) {
File projectFile = location.append( ".project" ).toFile();
// delete the .project if it exists. A new .project will be created.
if( projectFile.exists() ) {
projectFile.delete();
}
}
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IWorkspaceRoot workspaceRoot = workspace.getRoot();
IProject eclipseProjectHandler = workspaceRoot.getProject( name );
if( eclipseProjectHandler.exists() ) {
// this should not happen because we filter out the existing project
// on the import wizard
return eclipseProjectHandler;
}
try {
IProjectDescription projectDescription = createEclipseProjectDescription( name, location );
eclipseProjectHandler.create( projectDescription, new NullProgressMonitor() );
if( !eclipseProjectHandler.isOpen() ) {
eclipseProjectHandler.open( new NullProgressMonitor() );
}
// add natures
initiateProjectNature( eclipseProjectHandler );
// add builders
InternalImportUtils.initiateBuilders( eclipseProjectHandler );
} catch( Throwable t ) {
_log.error( t.getMessage(), t );
return null;
}
return eclipseProjectHandler;
}
static protected IClasspathEntry[] createSourceFolders( IProject eclipseProject, IPath[] sourceFolders ) {
IContainer projectContainer = eclipseProject.getProject(), sourceContainer = null;
IClasspathEntry[] sourceClasspathEntries = new IClasspathEntry[ sourceFolders.length ];
int i = 0;
for( IPath path : sourceFolders ) {
if( path.segmentCount() > 0 ) {
sourceContainer = projectContainer.getFolder( path );
if( !sourceContainer.exists() ) {
try {
( (IFolder) sourceContainer ).create( false, true, new NullProgressMonitor() );
} catch( CoreException e ) {
_log.error( e.getMessage(), e );
}
}
sourceClasspathEntries[ i++ ] = JavaCore.newSourceEntry( sourceContainer.getFullPath() );
}
}
return sourceClasspathEntries;
}
static public IProjectDescription createEclipseProjectDescription( String projectName, IPath projectLocation ) {
IProjectDescription projectDescription = ResourcesPlugin.getWorkspace().newProjectDescription( projectName );
// If it is in the platform workspace, then, we don't need to set this,
// since by _default_, the project will be created in the platform
// workspace. If the user has specifically customized this field when
// creating the project, then we set it here.
if( ( projectLocation != null ) )
projectDescription.setLocation( projectLocation.makeAbsolute() );
return projectDescription;
}
/**
* Creates a java project for the given <code>legacyProject</code>.
*
* @param legacyProject
* @param importType
* @param userLib
* @param REPath
* @param monitor
* @return
* @throws CoreException
*/
static public IJavaProject createJavaProject( Project legacyProject, int importType, String userLib, IPath REPath,
IProgressMonitor monitor ) throws CoreException {
IProject project = null;
if( importType == LegacyImportHelper.COPY_IMPORT ) {
project = createEclipseProjectHandler( legacyProject.getDisplayName(), null );
} else {
String name = legacyProject.getDisplayName();
IPath legacyProjectPath = getLocationPath( legacyProject );
IPath eclipseProjectPath = getLocationForEclipseProject( legacyProject, legacyProjectPath, true );
project = createEclipseProjectHandler( name, eclipseProjectPath );
}
return internalCreateJavaProject( legacyProject, project, importType, userLib, REPath, monitor );
}
/**
* Get the location of the Eclipse project. Returns the best possible location for the .project file to be created if one does
* not already exist.
*
* @param sourceProject
* @return
*/
public static IPath getLocationPath( Project sourceProject ) {
IPath folderPath;
IPath jdpPath = new Path( sourceProject.getFile().getAbsolutePath() );
// check if this is a multiple jdp scenario
// get an appropriate (closest to original) location to create the
// .project file.
folderPath = getLocationForEclipseProject( sourceProject, jdpPath.removeLastSegments( 1 ), true );
return folderPath;
}
/**
* Get the Location of .project file associated with this sourceProject or return the best possible path for the .project file
* to be created.
*
* @param sourceProject
* @param folderPath
* @param projectName
* @return
*/
static public IPath getLocationForEclipseProject( Project legacyProject, IPath folderPath, boolean safe ) {
String projectName = legacyProject.getDisplayName();
boolean folderExists = ( new File( folderPath.toOSString() ) ).exists();
if( folderExists ) {
if( safe ) {
boolean go = isMultipleJDP_Ws( folderPath ) || !isProjectFileValid( legacyProject, folderPath );
if( go ) {
// append the projectName as a new folder and see if it has
// MultipleJDPs and is not a valid .project file.
return getLocationForEclipseProject( legacyProject, folderPath.append( projectName ), safe );
}
}
}
return folderPath;
}
/**
* Determines if there are multiple JDPs .
*
* @param Folder
* - RIA project.
* @return - True if folder contains multiple JDPs or JDWs, false otherwise.
*
*/
static public boolean isMultipleJDP_Ws( IPath folderPath ) {
File folder = new File( folderPath.toOSString() );
if( !folder.exists() ) {// if the folder doesn't exist we know there
// can't be multiple JDPs in it.
return false;
}
File[] listOfFiles = folder.listFiles();
boolean isFirstJDP_W = true;// we expect to find one JDP.
String fileExtension;
File file;
for( int i = 0; i < listOfFiles.length; i++ ) {
file = listOfFiles[ i ];
if( file.isFile() ) {
fileExtension = ( new Path( file.getAbsolutePath() ) ).getFileExtension();
if( "jdp".equalsIgnoreCase( fileExtension ) || "jdw".equalsIgnoreCase( fileExtension ) ) {
if( isFirstJDP_W ) {
isFirstJDP_W = false; // the first JDP is found.
} else {
return true;// second JDP is found.
}
}
} else if( listOfFiles[ i ].isDirectory() ) {
// ignore this
}
}
return false;// no second JDP was found.
}
/**
* Validate if the .project file is in fact associated with sourceProject.
*
* @param sourceProject
* @param folder
* - Where the jdp for the sourceProject is located.
* @return True if the .project file is valid or not there. If there is no project file existing in the same directory, it is
* safe to assume that the new .project file created by the temporary project will be valid.
*/
static public boolean isProjectFileValid( Project sourceProject, IPath folder ) {
// check if validation is needed i.e. if there are other .project files
// in the same location
boolean projectFileExists = projectFileExists( folder );
if( !projectFileExists ) {
return true;
}
// validate .project file. It is possible that .project file here is not
// associated with this sourceProject
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IProjectDescription projectDescription = null;
try {
// simply loading the project description from the file is
// sufficient in this case.
// We do not need to create a temporary project for this.
projectDescription = workspace.loadProjectDescription( new Path( getProjectFile( folder ).getAbsolutePath() ) );
} catch( CoreException e ) {
_log.error( "Error occured while reading the Project description", e );
}
if( sourceProject.getDisplayName().equals( projectDescription.getName() ) ) {
return true;
} else {
return false;
}
}
/**
* Check to see if the .project file exists.
*
* @param folderPath
* @return
*/
static public boolean projectFileExists( IPath folderPath ) {
File folder = new File( folderPath.toOSString() );
if( !folder.exists() ) {// if the folder doesn't exist we know there
// can't be a .project file in it.
return false;
}
File[] listOfFiles = folder.listFiles();
String fileExtension;
for( int i = 0; i < listOfFiles.length; i++ ) {
if( listOfFiles[ i ].isFile() ) {
fileExtension = ( new Path( listOfFiles[ i ].getAbsolutePath() ) ).getFileExtension();
if( "project".equalsIgnoreCase( fileExtension ) ) {
return true;// .project file found.
}
} else if( listOfFiles[ i ].isDirectory() ) {
// ignore this
}
}
return false;// no project file exists.
}
/**
* Get the .project file located in the folderPath.
*
* @param folderPath
* @return - the .project file. null if the folderPath or file does not exist.
*/
static public File getProjectFile( IPath folderPath ) {
File folder = new File( folderPath.toOSString() );
if( !folder.exists() ) {// if the folder doesn't exist we know there
// can't be a .project file in it.
return null;
}
File[] listOfFiles = folder.listFiles();
String fileExtension;
for( int i = 0; i < listOfFiles.length; i++ ) {
if( listOfFiles[ i ].isFile() ) {
fileExtension = ( new Path( listOfFiles[ i ].getAbsolutePath() ) ).getFileExtension();
if( "project".equalsIgnoreCase( fileExtension ) ) {
return listOfFiles[ i ];// .project file found.
}
} else if( listOfFiles[ i ].isDirectory() ) {
// ignore this
}
}
return null;// no project file exists.
}
static protected IJavaProject internalCreateJavaProject( Project legacyProject, IProject project, int importType,
String userLib, IPath REPath, IProgressMonitor monitor ) throws CoreException {
try {
if( legacyProject == null )
throw new IllegalArgumentException( "Can't create Eclipse Java Project from undefind legacy project!" );
_log.debug( "Create IJavaProject [" + legacyProject.getDisplayName() + "]" );
monitor.beginTask( "Importing project " + legacyProject.getDisplayName(), 10 );
monitor.worked( 1 );
if( project == null )
return null;
// create a IJavaProject
IJavaProject eclipseJavaProject = JavaCore.create( project );
// set project options
initializeProjectOptions( eclipseJavaProject );
monitor.worked( 2 );
// get source folders, e.g. src and res
IPath[] defaultSources = getCustomSourceFolders( legacyProject );
// create classpath entries for source folders
IClasspathEntry[] sourceFolderEntries = createSourceFolders( project, defaultSources );
IClasspathEntry[] importedLibraries = resolveProjectImports( legacyProject, project );
String[] dependencies = getDependsOnProjectNames( legacyProject );
IClasspathEntry[] dependentProjects = resolveDependentProjects( dependencies );
IClasspathEntry[] jreEntries = getREClasspathEntries( REPath );
List< IClasspathEntry > classpathEntries = new ArrayList< IClasspathEntry >();
addEntryToList( classpathEntries, sourceFolderEntries );
addEntryToList( classpathEntries, importedLibraries );
addEntryToList( classpathEntries, dependentProjects );
addEntryToList( classpathEntries, jreEntries );
classpathEntries = applyExclusionPatterns( project, legacyProject, classpathEntries );
// add workspace imports as a user library
if( !StringUtils.isBlank( userLib ) ) {
UserLibrary library = JavaModelManager.getUserLibraryManager().getUserLibrary( userLib );
if( null != library ) {
IPath path = new Path( JavaCore.USER_LIBRARY_CONTAINER_ID ).append( userLib );
IClasspathEntry userLibEntry = JavaCore.newContainerEntry( path );
if( !classpathEntries.contains( userLibEntry ) ) {
classpathEntries.add( userLibEntry );
}
}
}
if( !eclipseJavaProject.isOpen() ) {
try {
eclipseJavaProject.open( new NullProgressMonitor() );
} catch( JavaModelException e ) {
_log.error( e.getMessage() );
throw new CoreException( StatusFactory.createErrorStatus( e.getMessage() ) );
}
}
setRawClassPath( eclipseJavaProject, classpathEntries.toArray( new IClasspathEntry[ classpathEntries.size() ] ) );
monitor.worked( 2 );
// link or copy files
if( importType == LegacyImportHelper.COPY_IMPORT ) {
copySourceFiles( legacyProject, eclipseJavaProject.getProject() );
int AEPNumber = legacyProject.getNumEntries();
// Copy AEP source files as well.
for( int i = 0; i < AEPNumber; i++ ) {
copySourceFiles( legacyProject.getEntry( i ), eclipseJavaProject.getProject() );
}
} else {
/**
* String: the package id, the container key. Set<File>: the files belonging to the package
* */
ResourcesBuffer resourcesBuffer;
resourcesBuffer = createProjectResourcesBuffer( legacyProject );
createBulkLinks( eclipseJavaProject, resourcesBuffer, legacyProject );
int AEPNumber = legacyProject.getNumEntries();
// link AEP source files as well.
for( int i = 0; i < AEPNumber; i++ ) {
resourcesBuffer = createProjectResourcesBuffer( legacyProject.getEntry( i ) );
createBulkLinks( eclipseJavaProject, resourcesBuffer, legacyProject.getEntry( i ) );
}
}
monitor.worked( 6 );
return eclipseJavaProject;
} finally {
monitor.done();
}
}
/**
*
* @param IJavaProject
* @param ResourcesBuffer
* @param project
*
* @throws IllegalArgumentException
* , NullPointerException for bounds and missing src directory
* */
static public void createBulkLinks( IJavaProject iJavaProject, ResourcesBuffer buffer, Project project ) {
if( null == iJavaProject )
throw new IllegalArgumentException( new NullPointerException( "Undefined java project!" ) );
if( null == buffer )
throw new IllegalArgumentException( new NullPointerException( "Undefined package container!" ) );
/**
*
* Processing all files
*
* */
List< LinkBuffer > linkBuffers = generateLinks( iJavaProject, buffer, project );
long start, end, total;
_log.debug( "Start creating links." );
start = System.currentTimeMillis();
for( LinkBuffer linkBuffer : linkBuffers ) {
linkBuffer.create();
}
end = System.currentTimeMillis();
total = end - start;
_log.debug( "Finished creating links in [" + total / 1000 + "] seconds." );
}
/**
* resources already in a source folder don't need a link, otherwise they'll be duplicated in bin/! jars will be handled by
* LIB type classpath
*
* @param packageResource
* : the Eclipse resource representing the package root
* @return boolean
*/
static private boolean isResourceTargetFolder( IResource packageResource ) {
return null != packageResource
&& packageResource.exists()
&& !ImportUtils.getImportPref( ResourceBuilder.LOCALE_INTERFACES_FOLDER_NAME ).equalsIgnoreCase(
packageResource.getName() );
}
/**
* resources already in a source folder don't need a link, otherwise they'll be duplicated in bin/! jars will be handled by
* LIB type classpath
*
* @param filePth
* : path to the file
* @param packageResource
* : the Eclipse resource representing the package segment
* @return boolean
*/
static private boolean canIgnoreFile( IPath filePath, IJavaProject eclipseJavaProject ) {
if( null == filePath ) {
throw new IllegalArgumentException( "Can't evaluate undefined path!" );
}
if( null == eclipseJavaProject || !eclipseJavaProject.exists() ) {
throw new IllegalArgumentException( "Can't evaluate undefined Eclipse JDT project!" );
}
if( IConstants.JAR_EXTENSION.equalsIgnoreCase( filePath.getFileExtension() ) )
return true;
return false;
}
static public IPath assureFolderPath( IFolder packageFolder, IPath rpath ) {
if( null == packageFolder )
throw new IllegalArgumentException( "Can't process undefined folder!" );
if( null == rpath )
throw new IllegalArgumentException( "Can't process undefined path!" );
IPath rfpath = rpath.removeLastSegments( 1 );
if( !packageFolder.exists( rfpath ) ) {
int segmentCount = rfpath.segmentCount();
boolean alternate = false;
String lfseg;
IResource[] members = null;
IFolder pfolder;
IPath rfpath_;
for( int i = 0; i < segmentCount; i++ ) {
rfpath_ = i < segmentCount - 1 ? rfpath.removeLastSegments( segmentCount - 1 - i ) : rfpath;
if( !packageFolder.exists( rfpath_ ) ) {
pfolder = packageFolder.getFolder( rfpath_ );
try {
pfolder.create( true, true, new NullProgressMonitor() );
} catch( CoreException e ) {
_log.error( e );
return null;
}
pfolder = packageFolder.getFolder( rfpath_.removeLastSegments( 1 ) );
try {
members = pfolder.members();
} catch( Throwable t ) {
_log.error( t.getMessage(), t );
return null;
}
for( IResource member : members ) {
if( IResource.FOLDER == member.getType()
&& ( lfseg = member.getFullPath().lastSegment() ).equalsIgnoreCase( rfpath_.lastSegment() ) ) {
alternate = true;
// substitute the case-mismatch segment
rfpath_ = rfpath.removeLastSegments( segmentCount - i ).append( lfseg );
if( i < segmentCount - 1 ) {
rfpath = rfpath_.append( rfpath.removeFirstSegments( i + 1 ) );
} else {
rfpath = rfpath_;
}
}
}
}
}
if( alternate ) {
rpath = rfpath.append( rpath.lastSegment() );
}
}
return rpath;
}
static public IFile createFileHandle( IFolder parent, String name ) {
if( null == parent )
throw new IllegalArgumentException( "Can't create handle for undefined parent!" );
if( StringUtils.isBlank( name ) )
throw new IllegalArgumentException( "Can't create handle for undefined name!" );
IWorkspaceRoot workspaceRoot = parent.getWorkspace().getRoot();
IPath fullPath = parent.getFullPath().append( name );
return workspaceRoot.getFile( fullPath );
}
static private List< LinkBuffer > generateLinks( IJavaProject eclipseJavaProject, ResourcesBuffer buffer,
Project legacyProject ) {
Map< String, Set< File >> javaArtifacts = buffer.getJavaContener();
Map< String, Set< File >> localeArtifacts = buffer.getlocaleContener();
Set< File > nonPackageableFiles = buffer.getNonPackageContener();
IPath drfpath = null, filePath = null;
IFile eclipseFileHandle = null, fileHandle = null;
IProject eclipseProject = eclipseJavaProject.getProject();
IWorkspaceRoot workspaceRoot = eclipseProject.getWorkspace().getRoot();
List< String > sources = net.rim.ejde.internal.legacy.Util.getSources( legacyProject );
IPackageFragmentRoot[] packageFragmentRoots;
IPackageFragment packageFragment;
IFolder packageFolder;
IResource resource, packageDirectory;
List< LinkBuffer > linkBuffers = Collections.emptyList();
try {
// packageFragmentRoots =
// eclipseJavaProject.getPackageFragmentRoots(); //!WARNING: it
// seems this is buggy!!!!
packageFragmentRoots = eclipseJavaProject.getAllPackageFragmentRoots();
linkBuffers = new ArrayList< LinkBuffer >();
String srcFolder = POTENTIAL_SOURCE_FOLDERS[ PROJECT_SRC_FOLDE_INDEX ];
String resFolder = POTENTIAL_SOURCE_FOLDERS[ PROJECT_RES_FOLDE_INDEX ];
String localeFolder = POTENTIAL_SOURCE_FOLDERS[ PROJECT_LOCALE_FOLDE_INDEX ];
IJavaProject javaProject = null;
for( IPackageFragmentRoot packageFragmentRoot : packageFragmentRoots ) {
javaProject = packageFragmentRoot.getParent().getJavaProject();
if( javaProject == null || !javaProject.equals( eclipseJavaProject ) ) {
// fixed DPI225325, we only care source folders in the
// current project
continue;
}
if( IPackageFragmentRoot.K_SOURCE == packageFragmentRoot.getKind() ) {
packageDirectory = packageFragmentRoot.getResource();
if( null != packageDirectory ) {
if( isResourceTargetFolder( packageDirectory ) ) {
if( IResource.FOLDER == packageDirectory.getType() ) {
// handle resource files which are not java, rrh
// and rrc
if( resFolder.equalsIgnoreCase( packageDirectory.getName() ) ) {
packageFragment = packageFragmentRoot.createPackageFragment( StringUtils.EMPTY, true,
new NullProgressMonitor() );
packageFolder = (IFolder) packageFragment.getResource();
for( File file : nonPackageableFiles ) {
filePath = new Path( file.getAbsolutePath() );
if( canIgnoreFile( filePath, eclipseJavaProject ) ) {
continue;
}
// drfpath = PackageUtils.resolvePathForFile( filePath, legacyProjectPath,
// legacyWorkspacePath ); // DPI222295
try {
drfpath = new Path( PackageUtils.getFilePackageString( filePath.toFile(),
legacyProject ) ).append( filePath.lastSegment() );
} catch( CoreException e ) {
_log.error( e.getMessage() );
drfpath = new Path( IConstants.EMPTY_STRING );
}
if( drfpath.segmentCount() > 1 ) {
if( sources.contains( drfpath.segment( 0 ) ) ) {
drfpath = drfpath.removeFirstSegments( 1 );
}
drfpath = assureFolderPath( packageFolder, drfpath );
}
fileHandle = createFileHandle( packageFolder, drfpath.toOSString() );
resource = eclipseProject.findMember( PackageUtils.deResolve( filePath,
eclipseProject.getLocation() ) );
if( resource != null )
eclipseFileHandle = workspaceRoot.getFile( resource.getFullPath() );
else
eclipseFileHandle = workspaceRoot.getFile( eclipseProject.getFullPath().append(
drfpath ) );
if( !fileHandle.equals( eclipseFileHandle ) ) {
linkBuffers.add( new LinkBuffer( fileHandle, filePath ) );
}
}
}
if( srcFolder.equalsIgnoreCase( packageDirectory.getName() )
|| srcFolder.equalsIgnoreCase( packageDirectory.getName() ) ) { // All
linkPackagableFiles( javaProject, packageFragmentRoot, javaArtifacts, linkBuffers );
}
if( localeFolder.equalsIgnoreCase( packageDirectory.getName() )
|| localeFolder.equalsIgnoreCase( packageDirectory.getName() ) ) {
linkPackagableFiles( javaProject, packageFragmentRoot, localeArtifacts, linkBuffers );
}
} else {
continue;
}
}
}
}
}
} catch( JavaModelException e1 ) {
_log.error( e1.getMessage(), e1 );
}
return linkBuffers;
}
static private void linkPackagableFiles( IJavaProject javaProject, IPackageFragmentRoot packageFragmentRoot,
Map< String, Set< File >> packagableContainer, List< LinkBuffer > linkBuffers ) throws JavaModelException {
IResource resource;
IFolder packageFolder;
IPath filePath = null;
IPath drfpath = null;
IFile eclipseFileHandle = null, fileHandle = null;
StringTokenizer tokenizer;
IPackageFragment packageFragment;
Set< File > packageableFiles;
Set< String > packageIds = packagableContainer.keySet();
for( String packageId : packageIds ) {
packageableFiles = packagableContainer.get( packageId );
if( StringUtils.isBlank( packageId ) ) {
packageId = "";
}
packageFragment = packageFragmentRoot.createPackageFragment( packageId, true, new NullProgressMonitor() );
if( IResource.FOLDER == packageFragment.getResource().getType() ) {
packageFolder = (IFolder) packageFragment.getResource();
for( File file : packageableFiles ) {
filePath = new Path( file.getAbsolutePath() );
if( canIgnoreFile( filePath, javaProject ) ) {
continue;
}
tokenizer = new StringTokenizer( packageId, "." );
drfpath = new Path( "" );
while( tokenizer.hasMoreElements() ) {
drfpath.append( tokenizer.nextToken() );
}
assureFolderPath( packageFolder, drfpath );
fileHandle = createFileHandle( packageFolder, file.getName() );
resource = javaProject.getProject().findMember(
PackageUtils.deResolve( filePath, javaProject.getProject().getLocation() ) );
if( resource != null )
eclipseFileHandle = javaProject.getProject().getWorkspace().getRoot().getFile( resource.getFullPath() );
else
eclipseFileHandle = null;
if( !fileHandle.equals( eclipseFileHandle ) ) {
linkBuffers.add( new LinkBuffer( fileHandle, filePath ) );
}
}
}
}
}
/**
* Creates a eclipse file link to the rim Project JDP file
*
* @param eclipseProject
* @param legacyProject
*/
static public void createFileLink( IProject eclipseProject, Project legacyProject ) {
IFile file = eclipseProject.getFile( legacyProject.getFile().getName() );
IPath absolutePath = new Path( legacyProject.getFile().getAbsolutePath() );
if( !file.exists() )
try {
file.createLink( absolutePath, IResource.NONE, new NullProgressMonitor() );
} catch( CoreException e ) {
_log.error( e.getMessage(), e );
}
}
static public ResourcesBuffer createProjectResourcesBuffer( Project project ) {
if( null == project )
throw new IllegalArgumentException( new NullPointerException( "Project can't be null!" ) );
int fileCount = project.getNumFiles();
Set< File > javaArtifacts = new TreeSet< File >();
Set< File > localeArtifacts = new TreeSet< File >();
Set< File > nonPackageableArtifacts = new TreeSet< File >();
List< String > phantomArtifacts = new ArrayList< String >();
WorkspaceFile workspaceFile;
File file;
String phantomArtifact = null;
for( int i = 0; i < fileCount; i++ ) {
workspaceFile = project.getSourceFile( i );
file = new File( OSUtils.replaceFileSeperator( workspaceFile.getFile().getAbsolutePath() ) );
if( !file.exists() ) {
try {
phantomArtifact = file.getCanonicalPath();
} catch( IOException e ) {
_log.error( e.getMessage(), e );
}
phantomArtifacts.add( "Missing file returned by legacy model [" + phantomArtifact + "]." );
continue;
}
if( workspaceFile.getIsJava() ) {
javaArtifacts.add( file );
continue;
} else if( workspaceFile.getIsResourceHeader() || workspaceFile.getIsLanguageResource() ) {
localeArtifacts.add( file );
continue;
}
nonPackageableArtifacts.add( file );
}
Map< String, Set< File >> javaContainer = buildPackageContainer( javaArtifacts );
Map< String, Set< File >> localeContainer = buildPackageContainer( localeArtifacts );
ResourcesBuffer resourcesBuffer;
resourcesBuffer = new ResourcesBuffer( javaContainer, localeContainer, nonPackageableArtifacts );
return resourcesBuffer;
}
/**
* Process Java packages and files declared by the corresponding *.jdp metadata of the legacy Project entity
*/
static public Map< String, Set< File >> buildPackageContainer( Set< File > legacyProjectFiles ) {
Map< String, Set< File >> container = new HashMap< String, Set< File >>();
Set< File > files;
String fileName = "", rrhFileName, packageId;
Map< RRHFile, Set< File >> rrcForRrhFiles = new HashMap< RRHFile, Set< File >>();
Map< String, String > rrhForPackageId = new HashMap< String, String >();
boolean isJava;
File directory;
File rrhFile;
RRHFile rrhFileTuple;
for( File file : legacyProjectFiles ) {
packageId = null;
if( null != file && file.exists() ) {
fileName = file.getName();
packageId = IConstants.EMPTY_STRING;
try {
/*
* .java,.rrh and.rrc files should be treated differently than any other files because.java file can have
* package declaration and.rrh file must have package declaration(requirement)and we treat rrc files based on
* rrh files package name.
*
* If the file is not.java or.rrh or.rrc then the package name will be empty string.
*/
if( PackageUtils.hasSourceExtension( fileName ) ) {
if( PackageUtils.hasRRCExtension( fileName ) ) {
if( fileName.contains( "_" ) ) {
rrhFileName = fileName.substring( 0, fileName.indexOf( '_' ) );
} else {
rrhFileName = fileName.substring( 0, fileName.indexOf( '.' ) );
}
directory = file.getParentFile();
if( directory.exists() && directory.isDirectory() ) {
rrhFile = new File( directory.getCanonicalPath() + File.separator + rrhFileName + ".rrh" );
if( rrhFile.exists() && rrhFile.isFile() ) {
try {
packageId = PackageUtils.getFilePackageString( rrhFile, null );
packageId = PackageUtils.convertPkgStringToID( packageId );
} catch( CoreException e ) {
_log.error( e.getMessage() );
packageId = IConstants.EMPTY_STRING;
}
rrhFileTuple = new RRHFile( rrhFileName, packageId );
files = rrcForRrhFiles.get( rrhFileTuple );
if( null == files ) {
files = new HashSet< File >();
rrcForRrhFiles.put( rrhFileTuple, files );
}
files.add( file );
}
}
continue;
}
isJava = PackageUtils.hasJavaExtension( fileName );
if( isJava || PackageUtils.hasRRHExtension( fileName ) ) {
try {
packageId = PackageUtils.getFilePackageString( file, null );
} catch( CoreException e ) {
_log.error( e.getMessage() );
}
packageId = PackageUtils.convertPkgStringToID( packageId );
// Is default package?
if( StringUtils.isBlank( packageId ) ) {
packageId = IConstants.EMPTY_STRING;
}
if( !isJava ) {
rrhForPackageId
.put( fileName.replaceAll( IConstants.RRH_FILE_EXTENSION_WITH_DOT, "" ), packageId );
}
files = container.get( packageId );
if( null == files ) {
files = new HashSet< File >();
container.put( packageId, files );
}
files.add( file );
}
} else {
// Is not a package-able artifact *.java/*.rrh/*.rrc
files = container.get( "" );
if( null == files ) {
files = new HashSet< File >();
container.put( "", files );
}
files.add( file );
continue;
}
} catch( Throwable e ) {
_log.error( e.getMessage(), e );
}
}
}// for
Set< String > rrhFileNames = rrhForPackageId.keySet();
Set< File > rrcFiles;
for( String rrhFileKey : rrhFileNames ) {
packageId = rrhForPackageId.get( rrhFileKey );
rrcFiles = rrcForRrhFiles.remove( rrhFileKey );
if( null == rrcFiles )
continue;
for( File rrcFile : rrcFiles ) {
files = container.get( packageId );
files.add( rrcFile );
}
}
if( !rrcForRrhFiles.isEmpty() ) {
Set< RRHFile > rrhFiles = rrcForRrhFiles.keySet();
// No package found then use the default package
// packageId = "";
rrhFile = null;
for( RRHFile rrhFileCursor : rrhFiles ) {
rrcFiles = rrcForRrhFiles.get( rrhFileCursor );
// create eg:- Theme.rrh
/*
* rrhFileName = rrhFileCursor._fileName + IConstants.RRH_FILE_EXTENSION_WITH_DOT;
*
* rrhPathStr = ""; rrcFileName = "";
*
* for( File extraFile : rrcFiles ) { rrhPathStr = extraFile.getAbsolutePath(); rrcFileName = extraFile.getName();
*
* break; }
*
* rrhPathStr = rrhPathStr.replace( rrcFileName, rrhFileName );
*
* / if( !StringUtils.isBlank( rrhPathStr ) ) { rrhFile = new File( rrhPathStr ); // This algorithm might fail on
* non-Windows system // because of possible case sensitivity issues. if( rrhFile.exists() ) { packageId =
* parseFileForPackageId( rrhFile ); } }
*/
files = container.get( rrhFileCursor._packageId );
if( null == files ) {
files = new HashSet< File >();
container.put( rrhFileCursor._packageId, files );
}
for( File extraFile : rrcFiles ) {
files.add( extraFile );
}
}
}
return container;
}
static public int hasResource( Project legacyProject ) {
int result = 0;
int nsf = legacyProject.getNumFiles();
WorkspaceFile wsFile;
for( int i = 0; i < nsf; i++ ) {
wsFile = legacyProject.getSourceFile( i );
if( wsFile.getIsJava() ) {
continue;
}
if( wsFile.getIsResourceHeader() || wsFile.getIsLanguageResource() ) {
if( ( result & HAS_LOCALE_FILE ) == 0 ) {
result = result | HAS_LOCALE_FILE;
if( ( result & HAS_RES_FILE ) != 0 ) {
return result;
}
}
continue;
}
if( ( result & HAS_RES_FILE ) == 0 ) {
result = result | HAS_RES_FILE;
if( ( result & HAS_LOCALE_FILE ) != 0 ) {
return result;
}
}
}
return result;
}
static protected IPath[] getCustomSourceFolders( Project legacyProject ) {
Set< IPath > sourcePathSet = new LinkedHashSet< IPath >();
sourcePathSet.add( new Path( POTENTIAL_SOURCE_FOLDERS[ PROJECT_SRC_FOLDE_INDEX ] ) );
String resFolderName = POTENTIAL_SOURCE_FOLDERS[ PROJECT_RES_FOLDE_INDEX ];
if( StringUtils.isNotBlank( resFolderName ) ) {
sourcePathSet.add( new Path( ImportUtils.getImportPref( LegacyImportHelper.PROJECT_RES_FOLDER_NAME_KEY ) ) );
}
String localeFolderName = POTENTIAL_SOURCE_FOLDERS[ PROJECT_LOCALE_FOLDE_INDEX ];
if( StringUtils.isNotBlank( localeFolderName ) ) {
sourcePathSet.add( new Path( ImportUtils.getImportPref( LegacyImportHelper.PROJECT_IMPORT_LOCALE_FOLDER_NAME_KEY ) ) );
}
return sourcePathSet.toArray( new IPath[ sourcePathSet.size() ] );
}
/**
* Get the IClasspathEntry for the give runtime environment path <code>REPath</code>.
*
* @param REPath
* @return
*/
static public IClasspathEntry[] getREClasspathEntries( IPath REPath ) {
if( REPath != null ) {
return new IClasspathEntry[] { JavaCore.newContainerEntry( REPath ) };
}
return PreferenceConstants.getDefaultJRELibrary();
}
static protected void addEntryToList( List< IClasspathEntry > entryList, IClasspathEntry[] entries ) {
for( int i = 0; i < entries.length; i++ ) {
if( entries[ i ] != null ) {
entryList.add( entries[ i ] );
}
}
}
static protected IClasspathEntry[] resolveDependentProjects( String[] dependencies ) {
IClasspathEntry[] sourceClasspathEntries = new IClasspathEntry[ dependencies.length ];
int i = 0;
for( String project : dependencies ) {
sourceClasspathEntries[ i++ ] = JavaCore.newProjectEntry( new Path( IConstants.BACK_SLASH_MARK + project ), true );
}
return sourceClasspathEntries;
}
/**
* Sets the given <code>classpathEntries</code> to the <code>eclipseJavaProject</code>.
*
* @param eclipseJavaProject
* @param classpathEntries
*/
static public void setRawClassPath( IJavaProject eclipseJavaProject, IClasspathEntry[] classpathEntries ) {
if( null == eclipseJavaProject )
throw new IllegalArgumentException( "Can't add classpath entries to undefined project!" );
if( null == classpathEntries )
throw new IllegalArgumentException( "Can't add undefined classpath entries to the project!" );
if( 0 == classpathEntries.length )
return;
try {
eclipseJavaProject.setRawClasspath( classpathEntries, new NullProgressMonitor() );
} catch( JavaModelException e ) {
_log.error( e.getMessage(), e );
}
}
/**
* Sets the RIM and Java project natures on the given project.
*
* @param project
* The Eclipse project to set the nature on
* @param monitor
* The workspace progress monitor
* @throws CoreException
*/
static public void initiateProjectNature( IProject project ) throws CoreException {
// Add BB core nature to the new BB Project if it is BB project
// This nature must be first so that the project will be properly decorated
if( !project.hasNature( BlackBerryProjectCoreNature.NATURE_ID ) ) {
addNatureToProject( project, BlackBerryProjectCoreNature.NATURE_ID, true );
}
// Add Preprocessing nature
if( !project.hasNature( BlackBerryProjectPreprocessingNature.NATURE_ID ) ) {
addNatureToProject( project, BlackBerryProjectPreprocessingNature.NATURE_ID, false );
}
// Add Java Nature
if( !project.hasNature( JavaCore.NATURE_ID ) ) {
addNatureToProject( project, JavaCore.NATURE_ID, false );
}
}
/**
* Helper method that installs a Project Nature onto a project.
*
* @param proj
* the Eclipse project
* @param natureId
* the ID of the project nature
* @param mustBeFirst
* whether the nature must be the first in the list. An icon must be first if the appropriate decorator is to be
* shown.
*
* @throws CoreException
* the core exception
*/
static public void addNatureToProject( IProject proj, String natureId, boolean mustBeFirst ) throws CoreException {
IProjectDescription description = proj.getDescription();
String[] prevNatures = description.getNatureIds();
String[] newNatures = new String[ prevNatures.length + 1 ];
if( mustBeFirst ) {
System.arraycopy( prevNatures, 0, newNatures, 1, prevNatures.length );
newNatures[ 0 ] = natureId;
} else {
System.arraycopy( prevNatures, 0, newNatures, 0, prevNatures.length );
newNatures[ prevNatures.length ] = natureId;
}
description.setNatureIds( newNatures );
proj.setDescription( description, new NullProgressMonitor() );
}
/**
* Sets a whole bunch of project specific settings.
* <p>
* http://help.eclipse.org/help31/topic/org.eclipse.jdt.doc.isv/reference/
* api/org/eclipse/jdt/core/JavaCore.html#getDefaultOptions()
*
* @param project
*/
@SuppressWarnings("unchecked")
static public void initializeProjectOptions( IJavaProject javaProject ) {
if( null == javaProject )
throw new IllegalArgumentException();
final Map map = javaProject.getOptions( false );
if( map.size() > 0 ) {
map.remove( JavaCore.COMPILER_COMPLIANCE );
map.remove( JavaCore.COMPILER_SOURCE );
map.remove( JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM );
}
map.put( JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_3 );
// DPI 221069 --> Bugzilla id=250185
map.put( JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_4 );
map.put( JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_2 );
javaProject.setOptions( map );
}
/**
* Gets the names of the projects which are depended by the <code>legacyProject</code>.
*
* @param legacyProject
* @return
*/
static public String[] getDependsOnProjectNames( Project legacyProject ) {
int dependsDirectlyOnCont = legacyProject.getNumDependsDirectlyOn();
String[] dependsOnProjectNames = new String[ dependsDirectlyOnCont ];
try {// for watherver reason - legayc API crashes etc, we don't want to
// create a case for NPE in the caller
String projectName;
for( int count = 0; count < dependsDirectlyOnCont; count++ ) {
projectName = legacyProject.getDependsDirectlyOn( count ).getDisplayName();
if( StringUtils.isNotBlank( projectName ) )
dependsOnProjectNames[ count ] = projectName;
else
_log.error( "Can't add an undefined project as dependency!" );
}
} catch( Throwable t ) {
_log.error( t.getMessage(), t );
}
return dependsOnProjectNames;
}
/**
* Gets the path of the potential source jar for the given library.
*
* @param libPath
* Path of a library jar
* @return The potential source jar for the given library
*/
public static IPath getSourceJarPath( IPath libPath ) {
if( libPath == null || libPath.isEmpty() ) {
return null;
}
IPath sourcePath;
String libraryName, sourceJarName;
libraryName = libPath.lastSegment();
sourceJarName = libraryName.substring( 0, libraryName.length() - 4 );
sourceJarName += "-sources.jar";
sourcePath = libPath.removeLastSegments( 1 ).append( sourceJarName );
return sourcePath;
}
/**
* Extracts a list of jar files that a RIM project needs on its build path. It does not actually assign the build path entries
* to the Eclipse project - it is up to the caller to do this.
*
* @param iProject
* the Eclipse project
* @param project
* the RIM project.
* @return a list of classpath entries representing import JAR files.
*/
@SuppressWarnings("unchecked")
static public IClasspathEntry[] resolveProjectImports( Project _project, IProject eclipseProject ) {
Vector< File > importJars = _project.getImports();
List< IClasspathEntry > jars = new ArrayList< IClasspathEntry >();
/**
* The file list can contain environment variables. Also, it is correct only to use file.getPath(). Using absolute paths
* with environment variables is a recipe for disaster.
*/
for( File importJar : importJars ) {
jars.add( addClassPathEntry( eclipseProject, new File( OSUtils.replaceFileSeperator( importJar.getPath() ) ), false ) );// Mac
// support
}
// also get [Files] .jar entries
File file;
String path;
int idx;
int numfiles = _project.getNumFiles();
for( int i = 0; i < numfiles; i++ ) {
file = _project.getSourceFile( i ).getFile();
path = file.getPath();
if( ( idx = path.lastIndexOf( '.' ) ) > 0 && ".jar".equalsIgnoreCase( path.substring( idx ) ) ) {
jars.add( addClassPathEntry( eclipseProject, file, true ) );
}
}
return jars.toArray( new IClasspathEntry[ jars.size() ] );
}
static public IClasspathEntry addClassPathEntry( IProject project, File importJar, boolean export ) {
String importJarPath = Util.replaceEnvVars( importJar.getPath() );
IPath importJarLocation = new Path( importJarPath );
int nms;
if( ( nms = project.getLocation().matchingFirstSegments( importJarLocation ) ) == project.getLocation().segmentCount() ) {
importJarLocation = project.getFile( importJarLocation.removeFirstSegments( nms ) ).getFullPath();
}
// check to ensure path is resolved
if( !importJarLocation.isAbsolute() ) {
if( "BBMProtocolTest".equalsIgnoreCase( project.getName() ) ) {
_log.debug( "found zombie BBMProtocolTest project!" );
}
String resolvedPath = EnvVarUtils.resolveVarToString( importJarLocation.toString() );
importJarLocation = EnvVarUtils.resolveVarToPath( resolvedPath );
_log.warn( "Can't add not absolute library path [" + importJarLocation + "]to the project classpath!" );
}
IPath sourceJarPath = getSourceJarPath( importJarLocation );
IClasspathEntry entry;
if( sourceJarPath == null || sourceJarPath.isEmpty() || !sourceJarPath.toFile().exists() ) {
entry = JavaCore.newLibraryEntry( importJarLocation, null, null, export );
} else {
entry = JavaCore.newLibraryEntry( importJarLocation, sourceJarPath, null, export );
}
return entry;
}
/**
* Returns the array of all referenced Projects for a given Project
*
* @param project
* the given Project
* @return the set of referenced Projects, calculated recursively
* @throws CoreException
* if an error occurs while computing referenced projects
*/
public static Set< Project > getAllReferencedProjects( Project project ) throws CoreException {
Set< Project > referencedProjects = new HashSet< Project >();
addReferencedProjects( project, referencedProjects );
return referencedProjects;
}
private static void addReferencedProjects( Project project, Set< Project > references ) throws CoreException {
Project refProject;
for( int i = 0; i < project.getNumDependsDirectlyOn(); i++ ) {
refProject = project.getDependsDirectlyOn( i );
if( !references.contains( refProject ) ) {
references.add( refProject );
addReferencedProjects( refProject, references );
}
}
}
/**
* Copies files form the <code>legacyProject</code> to the eclipse project <code>iproject</code>.
*
* @param legacyProject
* @param iproject
*/
static public void copySourceFiles( Project legacyProject, IProject iproject ) {
IPath srcFolderPath, resFolderPath, localeFolderPath;
File srcFile, headerFile;
WorkspaceFile wsFile;
int numSrcFiles = legacyProject.getNumFiles();
boolean isAbsolute;
String fileName;
File[] exportedLibs = null, libsBuffer = null;
IPath fileFolderPath, relpath = null;
srcFolderPath = new Path( POTENTIAL_SOURCE_FOLDERS[ PROJECT_SRC_FOLDE_INDEX ] );
resFolderPath = new Path( POTENTIAL_SOURCE_FOLDERS[ PROJECT_RES_FOLDE_INDEX ] );
localeFolderPath = new Path( POTENTIAL_SOURCE_FOLDERS[ PROJECT_LOCALE_FOLDE_INDEX ] );
for( int i = 0; i < numSrcFiles; i++ ) {
fileFolderPath = srcFolderPath;
wsFile = legacyProject.getSourceFile( i );
srcFile = new File( OSUtils.replaceFileSeperator( wsFile.getFile().getAbsolutePath() ) );// Mac support
fileName = srcFile.getName();
if( fileName.endsWith( ".jar" ) )/**
* Legacy model hack when an exported lib resides in the Files[...] section.
*/
{
_log.debug( "Project [" + legacyProject.getDisplayName() + "] has an exported library [" + fileName + "]." );
if( null == exportedLibs ) {
exportedLibs = new File[ 1 ];
exportedLibs[ 0 ] = srcFile;
} else {
libsBuffer = new File[ exportedLibs.length + 1 ];
System.arraycopy( exportedLibs, 0, libsBuffer, 0, exportedLibs.length );
libsBuffer[ exportedLibs.length ] = srcFile;
exportedLibs = libsBuffer;
}
continue;
}
isAbsolute = false;
// copy java and language files to their package declaration
// location
if( srcFile.exists() ) {
if( wsFile.getIsJava() ) {
// handle java files
fileFolderPath = getPackagePath( srcFolderPath, srcFile );
} else if( wsFile.getIsResourceHeader() ) {
// handle rrh files
fileFolderPath = getPackagePath( localeFolderPath, srcFile );
} else if( wsFile.getIsLanguageResource() ) {
// handle rrc files
headerFile = getResourceHeader( wsFile );
if( headerFile == null ) {
String err = "Can not find resource header file for "
+ OSUtils.replaceFileSeperator( wsFile.getFile().getAbsolutePath() );
_log.warn( err );
continue;
}
fileFolderPath = getPackagePath( localeFolderPath, headerFile ).removeLastSegments( 1 );
fileFolderPath = fileFolderPath.append( srcFile.getName() );
} else {
// handle other resource files which do not contain package information
if( isLinked( iproject, wsFile ) )
continue;
relpath = new Path( OSUtils.replaceFileSeperator( wsFile.toString() ) );
isAbsolute = relpath.isAbsolute();
if( !isAbsolute && 0 < relpath.segmentCount() ) {
try {
relpath = new Path( PackageUtils.getFilePackageString( srcFile, legacyProject ) ).append( relpath
.lastSegment() );
} catch( CoreException e ) {
_log.error( e.getMessage() );
relpath = new Path( IConstants.EMPTY_STRING );
}
}
// put key file in the source folder
if( wsFile.getIsKey() ) {
fileFolderPath = srcFolderPath.append( relpath );
} else {
if( StringUtils.isNotEmpty( POTENTIAL_SOURCE_FOLDERS[ PROJECT_RES_FOLDE_INDEX ] ) && !isAbsolute ) {
fileFolderPath = resFolderPath.append( relpath );
} else {
fileFolderPath = relpath;
}
}
}
} else {
String msg = "Can't parse undefined file or directory [" + srcFile.getAbsolutePath() + "]";
_log.error( msg );
}
if( !isAbsolute ) {
if( iproject.isOpen() )
createFolders( iproject.getLocation().toOSString(), fileFolderPath.removeLastSegments( 1 ) );
copyFile( iproject, srcFile, fileFolderPath );
}
if( ( wsFile.getIsResourceHeader() || wsFile.getIsLanguageResource() ) && !isLinked( iproject, wsFile ) )
// need to copy all associated rrc and rrh files, some of which
// may not be explicitly included in jdp
copyLocaleFiles( iproject, legacyProject, srcFile, fileFolderPath.removeLastSegments( 1 ) );
}
}
static private IPath getPackagePath( IPath newFilePath, File srcFile ) {
String packageId = IConstants.EMPTY_STRING;
;
try {
packageId = PackageUtils.getFilePackageString( srcFile, null );
} catch( CoreException e ) {
_log.error( e.getMessage() );
}
packageId = PackageUtils.convertPkgStringToID( packageId );
if( !StringUtils.isBlank( packageId ) ) {
packageId = packageId.replace( '.', IPath.SEPARATOR );
newFilePath = newFilePath.append( packageId );
}
newFilePath = newFilePath.append( srcFile.getName() );
return newFilePath;
}
static public boolean isLinked( IProject iProject, WorkspaceFile workspaceFile ) {
String projectName = iProject.getName();
String fileName = OSUtils.replaceFileSeperator( workspaceFile.getFile().getAbsolutePath() );
IFile file = getProjectBasedFileFromOSBasedFile( projectName, fileName );// Mac support
if( file == null ) // if the files is not found for the project, it is
// not linked
return false;
return file.isLinked();
}
/***
* Find file/linked file under a Eclipse project.
*
* @param projectName
* the name of project. If null, don't care which project this file belongs to
* @param osFilePathStr
* the file path string
* @return corresponding IFile object, or null if such file is not under any Eclipse project.
*/
public static IFile getProjectBasedFileFromOSBasedFile( String projectName, String osFilePathStr ) {
if( StringUtils.isEmpty( projectName ) ) {
return getProjectBasedFileFromOSBasedFile( osFilePathStr );
}
IFile result = null;
IPath location = Path.fromOSString( osFilePathStr );
IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocation( location );
for( int i = 0; i < files.length; i++ ) {
String currentProjectName = files[ i ].getProject().getName();
if( currentProjectName.equals( projectName ) ) {
result = files[ i ];
break;
}
}
return result;
}
/***
* Find file/linked file under a Eclipse workspace.
*
* @param osFilePathStr
* the file path string
* @return corresponding IFile object, or null if such file is not under any Eclipse project.
*/
public static IFile getProjectBasedFileFromOSBasedFile( String osFilePathStr ) {
IFile result = null;
IPath location = Path.fromOSString( osFilePathStr );
IFile[] files = ResourcesPlugin.getWorkspace().getRoot().findFilesForLocation( location );
if( files.length > 0 ) {
for( int i = 0; i < files.length; i++ ) {
if( files[ i ].getName().equals( location.lastSegment() ) ) {
result = files[ i ];
break;
}
}
if( result == null ) {
result = files[ 0 ]; // retrieve the first found file
}
}
return result;
}
static public File getResourceHeader( WorkspaceFile languageFile ) {
File[] resourceFiles = getResourceFiles( languageFile.getFile(), languageFile.getFile().getName() );
if( resourceFiles != null ) {
for( File file : resourceFiles )
if( file.getName().endsWith( IArtifacts.ILegacy.IDs.rrh.name() ) )
return file;
}
return null;
}
static public File[] getResourceFiles( final File origFile, String fileName ) {
final File srcDirectory = origFile.getParentFile();
final String fileNamePattern = getResourceFileNamePattern( fileName );
File[] resourceFiles = srcDirectory.listFiles( new FilenameFilter() {
public boolean accept( File dir, String name ) {
return !name.equals( origFile.getName() )
&& name.startsWith( fileNamePattern )
&& ( name.endsWith( IArtifacts.ILegacy.IDs.rrc.name() ) || name.endsWith( IArtifacts.ILegacy.IDs.rrh
.name() ) );
}
} );
return resourceFiles;
}
static public String getResourceFileNamePattern( String fileName ) {
int index = fileName.indexOf( '_' );
if( index == -1 )
return removeExtension( fileName );
else
return removeExtension( fileName.substring( 0, index ) );
}
static public String removeExtension( String fileName ) {
int index = fileName.lastIndexOf( '.' );
if( index == -1 )
return fileName;
else
return fileName.substring( 0, index );
}
/*
* Copies all rrc files associated with given rrh file to destFilePath
*
* @param iproject
*
* @param rrhFile
*
* @param destPath
*/
static public void copyLocaleFiles( IProject iproject, Project legacyProject, File origFile, IPath destPath ) {
String fileName = origFile.getName();
File[] resourceFiles = getResourceFiles( origFile, fileName );
if( resourceFiles != null ) {
for( int i = 0; i < resourceFiles.length; i++ )
createFolders( iproject.getLocation().toOSString(), destPath );
for( File resourceFile : resourceFiles )
copyFile( iproject, resourceFile, destPath.append( resourceFile.getName() ) );
}
}
static public void copyFile( IProject iproject, File srcFile, IPath newFilePath ) {
if( null == srcFile || !srcFile.exists() || srcFile.isDirectory() ) {
String msg = null == srcFile ? "" : srcFile.getPath();
_log.error( "Can't copy undefined file or directory [" + msg + "]" );
return;
}
if( null == iproject || !iproject.exists() ) {
String msg = null == iproject ? "" : iproject.getName();
_log.error( "Can't copy file [" + srcFile.getPath() + "] to undefined project [" + msg + "]" );
return;
}
if( null == newFilePath || newFilePath.isEmpty() ) {
String msg = null == newFilePath ? "" : newFilePath.toOSString();
_log.error( "Can't copy the file [" + srcFile.getPath() + "] to undefined path [" + msg + "]" );
return;
}
IFile iFile = iproject.getFile( newFilePath );
// if the file is there, do not copy
if( iFile.exists() ) {
return;
}
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream( srcFile );
IPath parent = newFilePath.removeLastSegments( 1 );
if( !parent.isEmpty() ) {
IFolder parentFolder = iproject.getFolder( parent );
if( !parentFolder.exists() ) {
ImportUtils.createFolders( iproject, parent, IResource.FORCE );
}
}
iFile.create( inputStream, IResource.FORCE, new NullProgressMonitor() );
iFile.refreshLocal( IResource.DEPTH_INFINITE, new NullProgressMonitor() );
} catch( Throwable e ) {
_log.error( e.getMessage(), e );
} finally {// just in case the Eclipse API doesn't close it for whatever
// reason.
try {
if( null != inputStream ) {
inputStream.close();
}
} catch( Throwable e ) {
;
_log.error( e.getMessage(), e );
}
}
}
static public void createFolders( String projectLocation, IPath newFilePath ) {
if( StringUtils.isBlank( projectLocation ) )
return;
File projectDirectory = new File( projectLocation ), newDirectory;
if( projectDirectory.exists() && projectDirectory.isDirectory() ) {
newDirectory = new File( projectDirectory.getAbsolutePath() + File.separator + newFilePath.toOSString() );
if( !newDirectory.exists() )
try {
newDirectory.mkdirs();
} catch( Throwable e ) {
_log.error( e.getMessage(), e );
}
}
}
static public IClasspathEntry createSourceEntry( IContainer sourceContainer ) {
IClasspathEntry entry = JavaCore.newSourceEntry( sourceContainer.getFullPath() );
return entry;
}
public static void createFolders( IProject project, IPath newFilePath, int updateFlags ) throws CoreException {
int numSegments = newFilePath.segmentCount();
for( int i = numSegments - 1; i >= 0; i-- ) {
IFolder folder = project.getFolder( newFilePath.removeLastSegments( i ) );
if( project.isOpen() && !folder.exists() ) {
folder.create( updateFlags, true, new NullProgressMonitor() );
}
}
}
public static void createFolders( IFolder parentFolder, IPath newFilePath, int updateFlags ) throws CoreException {
int numSegments = newFilePath.segmentCount();
for( int i = numSegments - 1; i >= 0; i-- ) {
IFolder folder = parentFolder.getFolder( newFilePath.removeLastSegments( i ) );
if( !folder.exists() ) {
folder.create( updateFlags, true, new NullProgressMonitor() );
}
}
}
public static IFolder createFolder( IFolder parent, IPath newFolder, int updateFlags ) throws CoreException {
if( newFolder == null || newFolder.toOSString().equals( IConstants.EMPTY_STRING ) ) {
return null;
}
IFolder folder = parent.getFolder( newFolder );
if( !folder.exists() ) {
folder.create( updateFlags, true, new NullProgressMonitor() );
}
return folder;
}
/**
* Get the preferences.ini key value
*
* @param key
* @return
*/
public static String getImportPref( String key ) {
return ContextManager.getDefault().getPreferenceStore().getString( key );
}
/**
* Get the prefereces.ini setting for res
*
* @return
*/
public static String getProjectResFolderName() {
return getImportPref( LegacyImportHelper.PROJECT_RES_FOLDER_NAME_KEY );
}
/**
* Get the preferences.ini key value as an int
*
* @param key
* @return
*/
public static int getIntImportPref( String key ) {
int npref = 0;
try {
npref = Integer.parseInt( getImportPref( key ) );
} catch( NumberFormatException e ) {
_log.warn( key + " preference is not initialized" );
}
return npref;
}
/**
* Get the set of output paths of the given <code>IProject</code>.
*
* @param project
* @return
* @throws JavaModelException
*/
static public Set< IPath > getOutputPathSet( IProject project ) throws JavaModelException {
return getOutputPathSet( JavaCore.create( project ) );
}
/**
* Get the set of output paths of the given <code>IJavaProject</code>.
*
* @param javaProject
* @return
* @throws JavaModelException
*/
static public Set< IPath > getOutputPathSet( IJavaProject javaProject ) {
HashSet< IPath > outputPathSet = new HashSet< IPath >();
try {
// get the output folder path of the project
IPath outputFolderPath = javaProject.getOutputLocation();
if( outputFolderPath != null ) {
outputPathSet.add( outputFolderPath );
}
IClasspathEntry[] _classPathEntries = javaProject.getRawClasspath();
IClasspathEntry entry;
for( int i = 0; i < _classPathEntries.length; i++ ) {
entry = _classPathEntries[ i ];
if( IClasspathEntry.CPE_SOURCE == entry.getEntryKind() ) {
// get the output folder of the entry
outputFolderPath = entry.getOutputLocation();
if( outputFolderPath != null ) {
outputPathSet.add( outputFolderPath );
}
}
}
} catch( JavaModelException e ) {
_log.debug( e.getMessage(), e );
}
return outputPathSet;
}
/**
* Get the set of output Files of the given <code>IJavaProject</code>.
*
* @param javaProject
* @return
*/
static public Set< File > getOutputFolderSet( IJavaProject javaProject ) {
Set< File > outputFolderFiles = new HashSet< File >();
Set< IPath > outputFolderSet = getOutputPathSet( javaProject );
IPath projectRelativePath;
for( IPath path : outputFolderSet ) {
// get rid of the first project segment
projectRelativePath = path.removeFirstSegments( 1 ).makeRelative();
outputFolderFiles.add( javaProject.getProject().getLocation().append( projectRelativePath ).toFile() );
}
return outputFolderFiles;
}
/**
* Check if the given <code>resource</code> is in one of the output folders of its project.
*
* @param resource
* @return
* @throws JavaModelException
*/
static public boolean isInOutputFolder( IResource resource, Set< IPath > outputPathSet ) throws JavaModelException {
for( Iterator< IPath > iterator = outputPathSet.iterator(); iterator.hasNext(); ) {
IPath path = iterator.next();
if( resource.getFullPath().matchingFirstSegments( path ) == path.segmentCount() )
return true;
}
return false;
}
static public final class ResourcesBuffer {
private final Map< String, Set< File >> _javaContainer;
private final Map< String, Set< File >> _localeContainer;
private final Set< File > _nonPackageContainer;
public ResourcesBuffer( Map< String, Set< File >> javaContainer, Map< String, Set< File >> localeContainer,
Set< File > nonPackageContainer ) {
if( null == javaContainer )
_javaContainer = Collections.emptyMap();
else
_javaContainer = javaContainer;
if( null == javaContainer )
_localeContainer = Collections.emptyMap();
else
_localeContainer = localeContainer;
if( null == nonPackageContainer )
_nonPackageContainer = Collections.emptySet();
else
_nonPackageContainer = nonPackageContainer;
}
public Map< String, Set< File >> getJavaContener() {
return _javaContainer;
}
public Map< String, Set< File >> getlocaleContener() {
return _localeContainer;
}
public Set< File > getNonPackageContener() {
return _nonPackageContainer;
}
}
static private class LinkBuffer {
IFile _fileHandle;
IPath _filePath;
LinkBuffer( IFile fileHandle, IPath filePath ) {
_fileHandle = fileHandle;
_filePath = filePath;
}
void create() {
try {
_fileHandle.createLink( _filePath, IResource.BACKGROUND_REFRESH | IResource.REPLACE
| IResource.ALLOW_MISSING_LOCAL, new NullProgressMonitor() );
} catch( CoreException e ) {
_log.error( e.getMessage(), e );
}
}
}
static final class RRHFile {
final String _fileName, _packageId;
RRHFile( String fileName, String packageId ) {
if( StringUtils.isEmpty( fileName ) )
throw new IllegalArgumentException( "" );
_fileName = fileName;
if( StringUtils.isEmpty( packageId ) )
_packageId = "";
else
_packageId = packageId;
}
@Override
public String toString() {
return "<" + RRHFile.class.getSimpleName() + "[_fileName=[" + _fileName + "], _packageId=[" + _packageId + "]>";
}
@Override
public boolean equals( Object other ) {
if( null == other )
return false;
if( RRHFile.class.equals( other.getClass() ) ) {
RRHFile theOther = (RRHFile) other;
return toString().equals( theOther.toString() );
}
return false;
}
@Override
public int hashCode() {
return ( _fileName + _packageId ).hashCode();
}
}
/**
* Applies the Java Path exclusion patterns to a given project and returns the list of filtered IClasspathEntry
*
* @param eclipseProject
* @param legacyProject
* @param originalClasspathEntries
* @return
*/
static public List< IClasspathEntry > applyExclusionPatterns( IProject eclipseProject, Project legacyProject,
List< IClasspathEntry > originalClasspathEntries ) {
if( null == eclipseProject ) {
throw new IllegalArgumentException( "Can't process undefined Eclipse project!" );
}
if( null == legacyProject ) {
throw new IllegalArgumentException( "Can't process undefined legacy project!" );
}
if( null == originalClasspathEntries ) {
throw new IllegalArgumentException( "Can't process undefined Eclipse classpath entries!" );
}
// TODO: call this when importing projects, rather than from the
// Compilation Participant
List< WorkspaceFile > excludedWorkspaceFiles = getFilesToBeExcluded( legacyProject );
if( excludedWorkspaceFiles.isEmpty() && originalClasspathEntries.isEmpty() ) {
return originalClasspathEntries;
}
List< IClasspathEntry > excludedClasspathEntries = new ArrayList< IClasspathEntry >();
HashMap< IPath, IClasspathEntry > filterMap = new HashMap< IPath, IClasspathEntry >();
String projectNamePattern = IPath.SEPARATOR + eclipseProject.getName() + IPath.SEPARATOR;
List< IPath > exclusionPatterns;
IPath classpathEntryPath, exclusionPatternPath;
boolean forProject;
String lastSegment;
IFolder folder;
IPath srcLocation;
IClasspathEntry newEntry;
IPath[] excludedPaths;
File file;
String workspaceFilePath;
String packageId;
for( IClasspathEntry entry : originalClasspathEntries ) {
exclusionPatterns = new ArrayList< IPath >();
classpathEntryPath = entry.getPath();
if( IClasspathEntry.CPE_SOURCE == entry.getEntryKind() ) {
lastSegment = classpathEntryPath.lastSegment();
if( lastSegment.equalsIgnoreCase( ImportUtils.getImportPref( ResourceBuilder.LOCALE_INTERFACES_FOLDER_NAME ) ) ) {
continue;
}
folder = eclipseProject.getFolder( lastSegment );
if( folder.isDerived() || !folder.exists() ) {
continue;
}
forProject = classpathEntryPath.toString().startsWith( projectNamePattern );
if( forProject ) {
srcLocation = folder.getLocation();
if( srcLocation == null || srcLocation.isEmpty() ) {
return originalClasspathEntries;
}
for( WorkspaceFile workspaceFile : excludedWorkspaceFiles ) {
workspaceFilePath = workspaceFile.toString();
file = workspaceFile.getFile();
if( null != file && file.exists() && file.isFile() ) {
// Fix for IDT 149988 - Check type of source folder and file type to prevent duplication for exclusion
// patterns
if( lastSegment.equalsIgnoreCase( ImportUtils
.getImportPref( LegacyImportHelper.PROJECT_SRC_FOLDER_NAME_KEY ) ) ) {
if( !workspaceFile.getIsJava() ) {
continue;
}
} else {
if( workspaceFile.getIsJava() ) {
continue;
}
}
if( workspaceFile.getIsJava() || workspaceFile.getIsResourceHeader() || workspaceFile.getIsResource() ) {
packageId = IConstants.EMPTY_STRING;
try {
packageId = PackageUtils.getFilePackageString( file, legacyProject );
} catch( CoreException e ) {
_log.error( e.getMessage() );
packageId = IConstants.EMPTY_STRING;
}
workspaceFilePath = File.separator + packageId + File.separator + workspaceFilePath;
}
exclusionPatternPath = getExclusionPattern( workspaceFile, lastSegment, eclipseProject, legacyProject );
if( !exclusionPatternPath.isEmpty() ) {
exclusionPatterns.add( exclusionPatternPath );
}
}
}
}
if( exclusionPatterns.isEmpty() ) {
excludedPaths = new IPath[] {};
} else {
excludedPaths = exclusionPatterns.toArray( new IPath[ exclusionPatterns.size() ] );
}
newEntry = JavaCore.newSourceEntry( classpathEntryPath, entry.getInclusionPatterns(), excludedPaths,
entry.getOutputLocation(), entry.getExtraAttributes() );
filterMap.put( classpathEntryPath, newEntry );
} else {// IClasspathEntry of type other than CPE_SOURCE
filterMap.put( classpathEntryPath, entry );
}
}
IPath elementPath;
for( IClasspathEntry element : originalClasspathEntries ) {
elementPath = element.getPath();
newEntry = filterMap.get( elementPath );
if( null != newEntry ) {
excludedClasspathEntries.add( newEntry );
}
}
return excludedClasspathEntries;
}
static private IPath getExclusionPattern( WorkspaceFile workspaceFile, String lastSegment, IProject project,
Project rimProject ) {
String file_str = IConstants.EMPTY_STRING;
String pkg_name = IConstants.EMPTY_STRING;
file_str = workspaceFile.toString();
File file;
if( workspaceFile.getIsJava() || workspaceFile.getIsResourceHeader() ) {
try {
pkg_name = PackageUtils.getFilePackageString( workspaceFile.getFile(), rimProject );
} catch( CoreException e ) {
_log.error( e.getMessage() );
}
if( StringUtils.isBlank( pkg_name ) ) {
file_str = workspaceFile.getFile().getName();
} else {
file_str = pkg_name + IConstants.FORWARD_SLASH_MARK + workspaceFile.getFile().getName();
}
file_str = trimFirstSlash( file_str );
} else if( workspaceFile.getIsLanguageResource() ) {// handle rrc files
String fileName = workspaceFile.getFile().getName();
String rrhFileName = IConstants.EMPTY_STRING;
String rrh_path = IConstants.EMPTY_STRING;
if( fileName.contains( "_" ) ) {
/*
* eg : - Theme_en. rrc
*/
rrhFileName = fileName.substring( 0, fileName.indexOf( '_' ) );
} else {
/*
* eg : - Theme . rrc
*/
rrhFileName = fileName.substring( 0, fileName.indexOf( '.' ) );
}
rrhFileName = rrhFileName + "." + IConstants.RRH_FILE_EXTENSION;
/*
* eg : - Theme . rrh
*/
rrh_path = workspaceFile.getFile().getAbsolutePath();
rrh_path = rrh_path.replace( fileName, rrhFileName );
if( rrh_path != null ) {
file = new File( rrh_path );
if( file.exists() && file.isFile() ) {
try {
pkg_name = PackageUtils.getFilePackageString( file, rimProject );
} catch( CoreException e ) {
_log.error( e.getMessage() );
}
}
}
if( StringUtils.isBlank( pkg_name ) ) {
file_str = workspaceFile.getFile().getName();
} else {
file_str = pkg_name + IConstants.FORWARD_SLASH_MARK + workspaceFile.getFile().getName();
}
file_str = trimFirstSlash( file_str ); // eg:- com/rim/test/A.java
} else {
IPath bbwkspath = ( new Path( rimProject.getWorkspace().getFile().toString() ) ).removeLastSegments( 1 );
IPath bbprjpath = ( new Path( rimProject.getFile().toString() ) ).removeLastSegments( 1 );
IPath resolvedFilePath = PackageUtils.resolvePathForFile( new Path( workspaceFile.getFile().getAbsolutePath() ),
bbprjpath, bbwkspath );
List< String > sources = getSources( rimProject );
String firstSegment = resolvedFilePath.segment( 0 );
if( sources.contains( firstSegment ) ) {
resolvedFilePath = resolvedFilePath.removeFirstSegments( 1 );
}
return resolvedFilePath;
}
return new Path( file_str );
}
static private String trimFirstSlash( String file_str ) {
if( ( file_str.startsWith( IConstants.PATH_SEPARATE_MARK ) ) || ( file_str.startsWith( IConstants.FORWARD_SLASH_MARK ) ) ) {
file_str = file_str.substring( 1 );
}
return file_str;
}
static public List< WorkspaceFile > getFilesToBeExcluded( Project rimProject ) {
List< WorkspaceFile > files = new ArrayList< WorkspaceFile >();
WorkspaceFile f;
for( int i = 0; i < rimProject.getNumFiles(); i++ ) {
f = rimProject.getSourceFile( i );
if( f.getDontBuild() )
files.add( f );
}
return files;
}
/**
* Returns a <code>List</code> of [UserData] sources
*
* @param proj
* @return
*/
static public List< String > getSources( Project proj ) {
List< String > sources = new ArrayList< String >();
String udata = proj.getUserData();
StringTokenizer st = new StringTokenizer( udata, "|" );
String token;
while( st.hasMoreElements() ) {
token = st.nextToken();
if( StringUtils.isNotBlank( token ) ) {
sources.add( token );
}
}
return sources;
}
/**
* Returns a boolean when ppList already contains the passed tag otherwise returns false
*
* @param ArrayList
* < PreprocessorTag > ppList
* @param String
* tag
* @return boolean
*/
static public boolean isPPtagsExists( ArrayList< PreprocessorTag > ppList, String tag ) {
for( PreprocessorTag ppTag : ppList ) {
if( ppTag.getPreprocessorDefine().equals( tag ) ) {
return true;
}
}
return false;
}
static public boolean isValidPPtag( String tag ) {
return validPPTagPattern.matcher( tag ).matches();
}
}