Java tutorial
/******************************************************************************* * Copyright 2011 Google Inc. All Rights Reserved. * * 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 * http://www.eclipse.org/legal/epl-v10.html * * 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.google.gdt.eclipse.maven.sdk; import com.google.gdt.eclipse.core.StatusUtilities; import com.google.gdt.eclipse.core.sdk.AbstractSdk; import com.google.gdt.eclipse.maven.Activator; import com.google.gdt.eclipse.maven.MavenUtils; import com.google.gwt.eclipse.core.launch.processors.GwtLaunchConfigurationProcessorUtilities; import com.google.gwt.eclipse.core.runtime.GWTRuntime.ProjectBoundSdk; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; /** * A project-based GWT SDK for Maven-based project. */ public class GWTMavenRuntime extends ProjectBoundSdk { public static final String MAVEN_GWT_GROUP_ID = "com.google.gwt"; public static final String MAVEN_GWT_DEV_JAR_ARTIFACT_ID = "gwt-dev"; public static final String MAVEN_GWT_USER_ARTIFACT_ID = "gwt-user"; public static final String MAVEN_GWT_SERVLET_ARTIFACT_ID = "gwt-servlet"; protected GWTMavenRuntime(IJavaProject javaProject) { super(javaProject); } @Override public URLClassLoader createClassLoader() throws SdkException, MalformedURLException { if (!validate().isOK()) { return new URLClassLoader(new URL[0]); } try { ArrayList<URL> classloaderURLs = new ArrayList<URL>(); // getDevJar would throw an exception instead of returning null // gwt-dev.jar classloaderURLs.add(getDevJar().toURI().toURL()); // findGwtUserClasspathEntry won't be null, because validate passed gwt-user.jar classloaderURLs.add(findGwtUserClasspathEntry().getPath().toFile().toURI().toURL()); // validation jars IClasspathEntry javaxValidationJar = findJavaXValidationClasspathEntry(); // could be null on older GWT projects if (javaxValidationJar != null) { classloaderURLs.add(javaxValidationJar.getPath().toFile().toURI().toURL()); } return new URLClassLoader(classloaderURLs.toArray(new URL[classloaderURLs.size()]), null); } catch (JavaModelException jme) { return new URLClassLoader(new URL[0]); } } /** * This method's implementation breaks the general contract of * {@link com.google.gwt.eclipse.core.runtime.GWTRuntime#getClasspathEntries()} . * * The general contract states that the entries returned should be the raw entries on the build * path that correspond to the SDK. This method returns the resolved entry on the build path that * corresponds to the gwt-user library. It then returns the path to the gwt-dev library that's a * peer of the gwt-user library in the Maven repository. This library may not be on the build * classpath. * * TODO: Reconsider the general contract of this method. * * TODO: Get rid of this method; I don't think its used at all in the Maven case. */ @Override public IClasspathEntry[] getClasspathEntries() { try { // If containers are being used, we avoid duplicates by using a set Set<IClasspathEntry> classpathEntries = new HashSet<IClasspathEntry>(); IClasspathEntry gwtUser = findGwtUserClasspathEntry(); if (gwtUser != null) { classpathEntries.add(gwtUser); File gwtDevJar = getDevJar(); if (gwtDevJar != null) { classpathEntries.add( JavaCore.newLibraryEntry(Path.fromOSString(gwtDevJar.getAbsolutePath()), null, null)); } } final List<IClasspathEntry> rawClasspath = Arrays.asList(javaProject.getRawClasspath()); // Sort the classpath entries so they match the declared order of the // raw classpath. IClasspathEntry[] classpathEntryArray = classpathEntries.toArray(NO_ICLASSPATH_ENTRIES); Collections.sort(Arrays.asList(classpathEntryArray), new Comparator<IClasspathEntry>() { @Override public int compare(IClasspathEntry o1, IClasspathEntry o2) { return rawClasspath.indexOf(o1) - rawClasspath.indexOf(o2); } }); return classpathEntryArray; } catch (JavaModelException e) { Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Unable to generate classpath entries for the maven-based GWT runtime.", e)); } catch (SdkException sdke) { Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Unable to generate classpath entries for the maven-based GWT runtime.", sdke)); } return AbstractSdk.NO_ICLASSPATH_ENTRIES; } @Override public File getDevJar() throws SdkException, JavaModelException { IClasspathEntry classpathEntry = findGwtUserClasspathEntry(); if (classpathEntry == null) { throw new SdkException("Unable to locate gwt-user.jar"); } IPath path = MavenUtils.getArtifactPathForPeerMavenArtifact(classpathEntry.getPath(), MAVEN_GWT_GROUP_ID, MAVEN_GWT_DEV_JAR_ARTIFACT_ID); if (path == null) { throw new SdkException("Unable to locate gwt-dev.jar"); } if (!path.toFile().exists()) { throw new SdkException(path.toOSString() + " does not exist."); } return path.toFile(); } /** * Maven-based GWT SDKs do not have a clear installation path. So, we say that the installation * path corresponds to: <code><repository path>/<group path></code>. */ @Override public IPath getInstallationPath() { try { IClasspathEntry classpathEntry = findGwtUserClasspathEntry(); if (classpathEntry == null) { return null; } IPath p = classpathEntry.getPath(); if (p.segmentCount() < 4) { return null; } return p.removeLastSegments(3); } catch (JavaModelException e) { Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Unable to determine installation path for the maven-based GWT runtime.", e)); } return null; } /** * Maven-based sdks do not contribute libraries that should be placed in the * <code>WEB-INF/lib</code> folder. */ @Override public File[] getWebAppClasspathFiles(IProject project) { return new File[0]; } @Override public IStatus validate() { try { getDevJar(); } catch (Exception e) { return StatusUtilities.newErrorStatus(e, Activator.PLUGIN_ID); } return StatusUtilities.OK_STATUS; } /** * Find the classpath for get-dev.jar which is used to run super dev mode. * * @return IClasspathEntry for the path to gwt-dev.jar * @throws JavaModelException */ private IClasspathEntry findGwtCodeServerClasspathEntry() throws JavaModelException { IType type = javaProject .findType(GwtLaunchConfigurationProcessorUtilities.SUPERDEVMODE_CODESERVER_MAIN_TYPE); if (type == null) { return null; } IPackageFragmentRoot packageFragmentRoot = (IPackageFragmentRoot) type .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); if (packageFragmentRoot.getKind() == IPackageFragmentRoot.K_BINARY) { return JavaCore.newLibraryEntry(packageFragmentRoot.getPath(), null, null); } return null; } private IClasspathEntry findGwtUserClasspathEntry() throws JavaModelException { /* * Note that the type that we're looking for to determine if we're part of the gwt-user library * is different than the one that is used by the superclass. This is because the class that the * superclass is querying for, "com.google.gwt.core.client.GWT", also exists in the gwt-servlet * library, and for some reason, this sometimes ends up on the build path for Maven projects. * * TODO: See why Maven is putting gwt-servlet on the build path. * * TODO: Change the class query in the superclass to "com.google.gwt.junit.client.GWTTestCase" */ IType type = javaProject.findType("com.google.gwt.junit.client.GWTTestCase"); if (type == null) { return null; } IPackageFragmentRoot packageFragmentRoot = (IPackageFragmentRoot) type .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); if (packageFragmentRoot.getKind() == IPackageFragmentRoot.K_BINARY) { // TODO: If the Maven javadoc and source libs for gwt-dev.jar are // available, attach them here. return JavaCore.newLibraryEntry(packageFragmentRoot.getPath(), null, null); } return null; } private IClasspathEntry findJavaXValidationClasspathEntry() throws JavaModelException { IType type = javaProject.findType("javax.validation.Constraint"); if (type == null) { return null; } IPackageFragmentRoot packageFragmentRoot = (IPackageFragmentRoot) type .getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT); if (packageFragmentRoot.getKind() == IPackageFragmentRoot.K_BINARY) { return JavaCore.newLibraryEntry(packageFragmentRoot.getPath(), null, null); } return null; } }