Java tutorial
/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.ide.eclipse.adt.internal.wizards.exportgradle; import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.AdtConstants; import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; import com.android.ide.eclipse.adt.internal.sdk.ProjectState; import com.android.ide.eclipse.adt.internal.sdk.ProjectState.LibraryState; import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.google.common.collect.Lists; import com.google.common.collect.Maps; 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.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import java.io.File; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.regex.Pattern; /** * Class to setup the project and its modules. */ public class ProjectSetupBuilder { private final static class InternalException extends Exception { private static final long serialVersionUID = 1L; InternalException(String message) { super(message); } } private boolean mCanFinish = false; private boolean mCanGenerate = false; private final List<GradleModule> mOriginalModules = Lists.newArrayList(); private final Map<IJavaProject, GradleModule> mModules = Maps.newHashMap(); private IPath mCommonRoot; private ExportStatus mStatus; public ProjectSetupBuilder() { } public void setCanGenerate(boolean generate) { mCanGenerate = generate; } public void setCanFinish(boolean canFinish) { mCanFinish = canFinish; } public boolean canFinish() { return mCanFinish; } public boolean canGenerate() { return mCanGenerate; } public void setStatus(ExportStatus status) { mStatus = status; } public ExportStatus getStatus() { return mStatus; } @NonNull public String setProject(@NonNull List<IJavaProject> selectedProjects) throws CoreException { mModules.clear(); // build a list of all projects that must be included. This is in case // some dependencies have not been included in the selected projects. We also include // parent projects so that the full multi-project setup is correct. // Note that if two projects are selected that are not related, both will be added // in the same multi-project anyway. try { for (IJavaProject javaProject : selectedProjects) { GradleModule module; if (javaProject.getProject().hasNature(AdtConstants.NATURE_DEFAULT)) { module = processAndroidProject(javaProject); } else { module = processJavaProject(javaProject); } mOriginalModules.add(module); } Collection<GradleModule> modules = mModules.values(); computeRootAndPaths(modules); return null; } catch (InternalException e) { return e.getMessage(); } } @NonNull public Collection<GradleModule> getModules() { return mModules.values(); } public int getModuleCount() { return mModules.size(); } @Nullable public IPath getCommonRoot() { return mCommonRoot; } @Nullable public GradleModule getModule(IJavaProject javaProject) { return mModules.get(javaProject); } public boolean isOriginalProject(@NonNull IJavaProject javaProject) { GradleModule module = mModules.get(javaProject); return mOriginalModules.contains(module); } @NonNull public List<GradleModule> getOriginalModules() { return mOriginalModules; } @Nullable public List<GradleModule> getShortestDependencyTo(GradleModule module) { return findModule(module, mOriginalModules); } @Nullable public List<GradleModule> findModule(GradleModule toFind, GradleModule rootModule) { if (toFind == rootModule) { List<GradleModule> list = Lists.newArrayList(); list.add(toFind); return list; } List<GradleModule> shortestChain = findModule(toFind, rootModule.getDependencies()); if (shortestChain != null) { shortestChain.add(0, rootModule); } return shortestChain; } @Nullable public List<GradleModule> findModule(GradleModule toFind, List<GradleModule> modules) { List<GradleModule> currentChain = null; for (GradleModule child : modules) { List<GradleModule> newChain = findModule(toFind, child); if (currentChain == null) { currentChain = newChain; } else if (newChain != null) { if (currentChain.size() > newChain.size()) { currentChain = newChain; } } } return currentChain; } @NonNull private GradleModule processAndroidProject(@NonNull IJavaProject javaProject) throws InternalException, CoreException { // get/create the module GradleModule module = createModuleOnDemand(javaProject); if (module.isConfigured()) { return module; } module.setType(GradleModule.Type.ANDROID); ProjectState projectState = Sdk.getProjectState(javaProject.getProject()); assert projectState != null; // add library project dependencies List<LibraryState> libraryProjects = projectState.getLibraries(); for (LibraryState libraryState : libraryProjects) { ProjectState libProjectState = libraryState.getProjectState(); if (libProjectState != null) { IJavaProject javaLib = getJavaProject(libProjectState); if (javaLib != null) { GradleModule libModule = processAndroidProject(javaLib); module.addDependency(libModule); } else { throw new InternalException(String.format( "Project %1$s is missing. Needed by %2$s.\n" + "Make sure all dependencies are opened.", libraryState.getRelativePath(), javaProject.getProject().getName())); } } else { throw new InternalException(String.format( "Project %1$s is missing. Needed by %2$s.\n" + "Make sure all dependencies are opened.", libraryState.getRelativePath(), javaProject.getProject().getName())); } } // add java project dependencies List<IJavaProject> javaDepProjects = getReferencedProjects(javaProject); for (IJavaProject javaDep : javaDepProjects) { GradleModule libModule = processJavaProject(javaDep); module.addDependency(libModule); } return module; } @NonNull private GradleModule processJavaProject(@NonNull IJavaProject javaProject) throws InternalException, CoreException { // get/create the module GradleModule module = createModuleOnDemand(javaProject); if (module.isConfigured()) { return module; } module.setType(GradleModule.Type.JAVA); // add java project dependencies List<IJavaProject> javaDepProjects = getReferencedProjects(javaProject); for (IJavaProject javaDep : javaDepProjects) { // Java project should not reference Android project! if (javaDep.getProject().hasNature(AdtConstants.NATURE_DEFAULT)) { throw new InternalException(String.format( "Java project %1$s depends on Android project %2$s!\n" + "This is not a valid dependency", javaProject.getProject().getName(), javaDep.getProject().getName())); } GradleModule libModule = processJavaProject(javaDep); module.addDependency(libModule); } return module; } private void computeRootAndPaths(Collection<GradleModule> modules) throws InternalException { // compute the common root. mCommonRoot = determineCommonRoot(modules); // compute all the relative paths. for (GradleModule module : modules) { String path = getGradlePath(module.getJavaProject().getProject().getLocation(), mCommonRoot); module.setPath(path); } } /** * Finds the common parent directory shared by this project and all its dependencies. * If there's only one project, returns the single project's folder. * @throws InternalException */ @NonNull private static IPath determineCommonRoot(Collection<GradleModule> modules) throws InternalException { IPath commonRoot = null; for (GradleModule module : modules) { if (commonRoot == null) { commonRoot = module.getJavaProject().getProject().getLocation(); } else { commonRoot = findCommonRoot(commonRoot, module.getJavaProject().getProject().getLocation()); } } return commonRoot; } /** * Converts the given path to be relative to the given root path, and converts it to * Gradle project notation, such as is used in the settings.gradle file. */ @NonNull private static String getGradlePath(IPath path, IPath root) { IPath relativePath = path.makeRelativeTo(root); String relativeString = relativePath.toOSString(); return ":" + relativeString.replaceAll(Pattern.quote(File.separator), ":"); //$NON-NLS-1$ } /** * Given two IPaths, finds the parent directory of both of them. * @throws InternalException */ @NonNull private static IPath findCommonRoot(@NonNull IPath path1, @NonNull IPath path2) throws InternalException { if (path1.getDevice() != null && !path1.getDevice().equals(path2.getDevice())) { throw new InternalException("Different modules have been detected on different drives.\n" + "This prevents finding a common root to all modules."); } IPath result = path1.uptoSegment(0); final int count = Math.min(path1.segmentCount(), path2.segmentCount()); for (int i = 0; i < count; i++) { if (path1.segment(i).equals(path2.segment(i))) { result = result.append(Path.SEPARATOR + path2.segment(i)); } } return result; } @Nullable private IJavaProject getJavaProject(ProjectState projectState) { try { return BaseProjectHelper.getJavaProject(projectState.getProject()); } catch (CoreException e) { return null; } } @NonNull private GradleModule createModuleOnDemand(@NonNull IJavaProject javaProject) { GradleModule module = mModules.get(javaProject); if (module == null) { module = new GradleModule(javaProject); mModules.put(javaProject, module); } return module; } @NonNull private static List<IJavaProject> getReferencedProjects(IJavaProject javaProject) throws JavaModelException, InternalException { List<IJavaProject> projects = Lists.newArrayList(); IClasspathEntry entries[] = javaProject.getRawClasspath(); for (IClasspathEntry classpathEntry : entries) { if (classpathEntry.getContentKind() == IPackageFragmentRoot.K_SOURCE && classpathEntry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { // found required project on build path String subProjectRoot = classpathEntry.getPath().toString(); IJavaProject subProject = getJavaProject(subProjectRoot); // is project available in workspace? if (subProject != null) { projects.add(subProject); } else { throw new InternalException(String.format( "Project '%s' is missing project dependency '%s' in Eclipse workspace.\n" + "Make sure all dependencies are opened.", javaProject.getProject().getName(), classpathEntry.getPath().toString())); } } } return projects; } /** * Get Java project for given root. */ @Nullable private static IJavaProject getJavaProject(String root) { IPath path = new Path(root); if (path.segmentCount() == 1) { return getJavaProjectByName(root); } IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(path); if (resource != null && resource.getType() == IResource.PROJECT) { if (resource.exists()) { return (IJavaProject) JavaCore.create(resource); } } return null; } /** * Get Java project from resource. */ private static IJavaProject getJavaProjectByName(String name) { try { IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(name); if (project.exists()) { return JavaCore.create(project); } } catch (IllegalArgumentException iae) { } return null; } }