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.designer.hosted.tdz; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URL; import java.util.List; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.swt.widgets.Display; import org.osgi.framework.Bundle; import com.google.gdt.eclipse.designer.hosted.HostedModeException; import com.google.gdt.eclipse.designer.hosted.IBrowserShell; import com.google.gdt.eclipse.designer.hosted.IBrowserShellFactory; import com.google.gdt.eclipse.designer.hosted.IHostedModeSupport; import com.google.gdt.eclipse.designer.hosted.ILogSupport; import com.google.gdt.eclipse.designer.hosted.IModuleDescription; import com.google.gdt.eclipse.designer.hosted.classloader.GWTSharedClassLoader; import com.google.gdt.eclipse.designer.hosted.tdz.log.LogSupport; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.linker.ArtifactSet; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.dev.cfg.BindingProperty; import com.google.gwt.dev.cfg.ModuleDef; import com.google.gwt.dev.cfg.ModuleDefLoader; import com.google.gwt.dev.cfg.Properties; import com.google.gwt.dev.cfg.Property; import com.google.gwt.dev.javac.CompilationState; import com.google.gwt.dev.shell.ArtifactAcceptor; import com.google.gwt.dev.shell.CompilingClassLoader; import com.google.gwt.dev.shell.ModuleSpace; import com.google.gwt.dev.shell.ModuleSpaceHost; import com.google.gwt.dev.shell.ShellModuleSpaceHost; import org.eclipse.wb.core.utils.external.ExternalFactoriesHelper; import org.eclipse.wb.internal.core.utils.IOUtils2; import org.eclipse.wb.internal.core.utils.reflect.ProjectClassLoader; /** * Implementation for {@link IHostedModeSupport} for GWT 2.0. Also used as {@link IBrowserShellHost} while * creating {@link ModuleSpace} for current platform. * * @author mitin_aa */ public final class HostedModeSupport implements IHostedModeSupport, IBrowserShellHost { private static GWTSharedClassLoader m_gwtSharedClassLoader; private final ClassLoader m_parentClassLoader; private final IModuleDescription m_moduleDescription; private final BrowserShell m_browserShell; private final IJavaProject m_javaProject; private ProjectClassLoader m_devClassLoader; private ShellModuleSpaceHost m_moduleSpaceHost; private File m_shellDirectory; private final LogSupport m_logSupport; private ModuleDef m_moduleDef; private TypeOracle m_typeOracle; //////////////////////////////////////////////////////////////////////////// // // Constructor // //////////////////////////////////////////////////////////////////////////// public HostedModeSupport(ClassLoader parentClassLoader, IModuleDescription moduleDescription) throws Exception { m_parentClassLoader = parentClassLoader; m_moduleDescription = moduleDescription; m_javaProject = moduleDescription.getJavaProject(); // Logger m_logSupport = new LogSupport(TreeLogger.TRACE, m_javaProject); // Class loaders createClassLoaders(); // Browser shell m_browserShell = (BrowserShell) createBrowserShell(); m_browserShell.setHost(this); } //////////////////////////////////////////////////////////////////////////// // // ClassLoaders // //////////////////////////////////////////////////////////////////////////// /** * Creates the special {@link ClassLoader}'s to work with GWT "dev" classes and "user" classes. */ private void createClassLoaders() throws Exception { m_devClassLoader = ProjectClassLoader.create(getSharedClassLoader(), m_javaProject); { Bundle bundle = Platform.getBundle("com.google.gdt.eclipse.designer.hosted.2_0.super"); URL rootEntry = bundle.getEntry(""); rootEntry = FileLocator.toFileURL(rootEntry); m_devClassLoader.addURL(rootEntry); } } //////////////////////////////////////////////////////////////////////////// // // IHostedModeSupport // //////////////////////////////////////////////////////////////////////////// public void startup(String browserStartupUrl, String moduleName, IProgressMonitor monitor, int timeout) throws Exception { CompilingClassLoader.parentClassLoader = m_parentClassLoader; try { //long l = System.currentTimeMillis(); m_browserShell.setUrl(browserStartupUrl, moduleName, timeout, new Runnable() { public void run() { runMessagesLoop(); } }); //System.out.println("\tstartup time: " + (System.currentTimeMillis() - l)); } finally { CompilingClassLoader.parentClassLoader = null; } } public void dispose() { m_browserShell.dispose(); // dispose if initialized (may be not if Module loading failed) if (m_moduleSpaceHost != null) { m_moduleSpaceHost.getModuleSpace().dispose(); } // dispose for project; if the same project used in another editor // it would be added again by activating the project. m_gwtSharedClassLoader.dispose(m_moduleDescription); m_logSupport.dispose(); m_moduleSpaceHost = null; // clear static caches try { Class<?> clazz = m_gwtSharedClassLoader.loadClass("com.google.gwt.i18n.rebind.ClearStaticData"); Method method = clazz.getDeclaredMethod("clear"); method.setAccessible(true); method.invoke(null); } catch (Throwable e) { } try { Class<?> clazz = m_gwtSharedClassLoader .loadClass("com.google.gwt.uibinder.rebind.model.OwnerFieldClass"); Field mapField = clazz.getDeclaredField("FIELD_CLASSES"); mapField.setAccessible(true); Map<?, ?> map = (Map<?, ?>) mapField.get(null); map.clear(); } catch (Throwable e) { } } public IBrowserShell getBrowserShell() { return m_browserShell; } public ClassLoader getClassLoader() { return m_moduleSpaceHost.getClassLoader(); } public ClassLoader getDevClassLoader() { return m_devClassLoader; } public Object findJType(String name) { return m_typeOracle.findType(name); } private ClassLoader getSharedClassLoader() throws Exception { // shared class loader for gwt-user.jar if (m_gwtSharedClassLoader == null) { m_gwtSharedClassLoader = new GWTSharedClassLoader(ModuleDef.class.getClassLoader(), new URL[] {}); } activate(); return m_gwtSharedClassLoader; } public void invalidateRebind(String typeName) { } public void activate() throws Exception { m_gwtSharedClassLoader.setActiveProject(m_moduleDescription); ModuleSpace.setLogger(getLogger()); } public byte[] getGeneratedResource(String resourceName) throws Exception { File resourceFile = new File(m_shellDirectory, resourceName); if (!resourceFile.exists()) { return null; } return IOUtils2.readBytes(resourceFile); } public ILogSupport getLogSupport() { return m_logSupport; } //////////////////////////////////////////////////////////////////////////// // // BrowserShell // //////////////////////////////////////////////////////////////////////////// /** * Creates and returns the {@link IBrowserShell} instance for current platform using external factory. */ @SuppressWarnings("unchecked") private IBrowserShell createBrowserShell() throws Exception { List<IBrowserShellFactory> factories = ExternalFactoriesHelper.getElementsInstances( IBrowserShellFactory.class, "com.google.gdt.eclipse.designer.hosted.2_0.browserShellFactory", "factory"); for (IBrowserShellFactory factory : factories) { IBrowserShell shell = factory.create(); if (shell != null) { return shell; } } // no shell has been created by factories if (isWindows64()) { // special message for windows throw new HostedModeException(HostedModeException.WIN32_NO_WINDOWS_64); } throw new HostedModeException(HostedModeException.UNSUPPORTED_OS); } /** * @return <code>true</code> while running Windows 64-bit. */ private boolean isWindows64() { String osName = System.getProperty("os.name"); String archName = System.getProperty("os.arch"); if (!StringUtils.isEmpty(osName) && !StringUtils.isEmpty(archName)) { return osName.startsWith("Windows") && archName.indexOf("64") != -1; } return false; } /** * Forces an outstanding messages to be processed */ public void runMessagesLoop() { try { while (Display.getCurrent().readAndDispatch()) { // wait } } catch (Throwable e) { } } //////////////////////////////////////////////////////////////////////////// // // IBrowserShellHost // //////////////////////////////////////////////////////////////////////////// //private final Set<String> alreadySeenModules = new HashSet<String>(); /** * Load a module. * * @param moduleName * a Name of the module to load. * @param outDir * @return the loaded module. */ private ModuleDef loadModule(String moduleName) throws Exception { //boolean assumeFresh = !alreadySeenModules.contains(moduleName); ModuleDef moduleDef = ModuleDefLoader.loadFromClassPath(getLogger(), moduleName, true/*!assumeFresh*/); //alreadySeenModules.add(moduleName); assert moduleDef != null : "Required module state is absent"; return moduleDef; } public ModuleSpaceHost createModuleSpaceHost(final String moduleName) throws Exception { ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(m_devClassLoader); try { // Try to find an existing loaded version of the module def. // String outDir = getTemporaryDirectoryName(m_javaProject); m_moduleDef = loadModule(moduleName); assert m_moduleDef != null; fixUserAgentProperty(m_moduleDef); // TODO uncomment, if want to see/debug generators, like UiBinder //File genDir = new File(outDir); File genDir = null; // Create a sandbox for the module. m_shellDirectory = new File(outDir, ".tmp" + File.separator + "shell" + File.separator + moduleName); CompilationState compilationState = m_moduleDef.getCompilationState(getLogger()); m_typeOracle = compilationState.getTypeOracle(); m_moduleSpaceHost = new ShellModuleSpaceHost(getLogger(), compilationState, m_moduleDef, genDir, m_shellDirectory, new ArtifactAcceptor() { public void accept(TreeLogger logger, ArtifactSet newlyGeneratedArtifacts) throws UnableToCompleteException { // TODO: does we need this? } }); return m_moduleSpaceHost; } finally { Thread.currentThread().setContextClassLoader(oldContextClassLoader); } } /** * Forcibly set 'user.agent' property to current platform. * http://fogbugz.instantiations.com/fogbugz/default.php?41513 */ private void fixUserAgentProperty(ModuleDef module) { Properties properties = module.getProperties(); for (Property property : properties) { if ("user.agent".equals(property.getName())) { BindingProperty bindingProperty = (BindingProperty) property; bindingProperty.setAllowedValues(bindingProperty.getRootCondition(), m_browserShell.getUserAgentString()); return; } } } public TreeLogger getLogger() { return (TreeLogger) m_logSupport.getLogger(); } //////////////////////////////////////////////////////////////////////////// // // Utils // //////////////////////////////////////////////////////////////////////////// public static String getTemporaryDirectoryName(IJavaProject javaProject) { String logDir = javaProject.getProject().getLocation().toOSString() + File.separator + ".gwt"; File logDirFile = new File(logDir); logDirFile.mkdirs(); return logDir; } //////////////////////////////////////////////////////////////////////////// // // IHostedModeSupport, invocations of native code. // //////////////////////////////////////////////////////////////////////////// @SuppressWarnings("rawtypes") public boolean invokeNativeBoolean(String string, Class[] classes, Object[] objects) { try { return m_moduleSpaceHost.getModuleSpace().invokeNativeBoolean(string, null, classes, objects); } catch (Throwable e) { throw new RuntimeException(e); } } @SuppressWarnings("rawtypes") public String invokeNativeString(String string, Class[] classes, Object[] objects) { try { return (String) m_moduleSpaceHost.getModuleSpace().invokeNativeObject(string, null, classes, objects); } catch (Throwable e) { throw new RuntimeException(e); } } @SuppressWarnings("rawtypes") public void invokeNativeVoid(String string, Class[] classes, Object[] objects) { try { m_moduleSpaceHost.getModuleSpace().invokeNativeVoid(string, null, classes, objects); } catch (Throwable e) { throw new RuntimeException(e); } } }