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.model.widgets.support; import com.google.common.collect.Lists; import com.google.gdt.eclipse.designer.Activator; import com.google.gdt.eclipse.designer.IExceptionConstants; import com.google.gdt.eclipse.designer.common.Constants; import com.google.gdt.eclipse.designer.hosted.IBrowserShell; import com.google.gdt.eclipse.designer.hosted.IHostedModeSupport; import com.google.gdt.eclipse.designer.hosted.IHostedModeSupportFactory; import com.google.gdt.eclipse.designer.model.module.ModuleElement; import com.google.gdt.eclipse.designer.model.module.PropertyProviderElement; import com.google.gdt.eclipse.designer.support.http.HttpServer; import com.google.gdt.eclipse.designer.support.http.IModuleInitializer; import com.google.gdt.eclipse.designer.support.http.IResourceProvider; import com.google.gdt.eclipse.designer.util.ModuleDescription; import com.google.gdt.eclipse.designer.util.ModuleVisitor; import com.google.gdt.eclipse.designer.util.Utils; import com.google.gdt.eclipse.designer.util.resources.IResourcesProvider; import org.eclipse.wb.core.editor.IDesignPageSite; import org.eclipse.wb.draw2d.geometry.Dimension; import org.eclipse.wb.draw2d.geometry.Insets; import org.eclipse.wb.draw2d.geometry.Point; import org.eclipse.wb.draw2d.geometry.Rectangle; import org.eclipse.wb.internal.core.DesignerPlugin; import org.eclipse.wb.internal.core.utils.IOUtils2; import org.eclipse.wb.internal.core.utils.Version; import org.eclipse.wb.internal.core.utils.exception.DesignerException; import org.eclipse.wb.internal.core.utils.execution.ExecutionUtils; import org.eclipse.wb.internal.core.utils.execution.RunnableEx; import org.eclipse.wb.internal.core.utils.external.ExternalFactoriesHelper; import org.eclipse.wb.internal.core.utils.reflect.ReflectionUtils; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import java.io.InputStream; import java.lang.reflect.Field; import java.util.List; /** * Provides access to the GWT module, hosted mode {@link ClassLoader} and many other low level * things. * * @author mitin_aa * @author scheglov_ke * @coverage gwt.model */ public final class GwtState { private static final String CLASSPATH_URL_MARKER = "/__classpath__/"; private static final String START_HTML = "__start.html"; // errors for last state private static String m_loggerErrorMessages; // for tests public static final List<GwtState> INSTANCES = Lists.newArrayList(); public final String m_testQualifiedName; // from constructor private final ClassLoader m_parentClassLoader; private final Version m_version; private final IJavaProject m_javaProject; private final ModuleDescription m_moduleDescription; private String m_moduleId; private String m_moduleName; private final CssSupport m_cssSupport = new CssSupport(this); // HTML private static int m_nextStateIndex = 0; protected final String m_moduleBaseURL = "/" + m_nextStateIndex++ + "/"; private final String m_startHtmlUrl = m_moduleBaseURL + START_HTML; private boolean m_strictMode; private String m_html; // hosted mode private boolean m_initialized; private IBrowserShell m_shell; private IHostedModeSupport m_hostModeSupport; private final DOMUtils m_domUtils = new DOMUtils(this); private final UIObjectUtils m_uiObjectUtils = new UIObjectUtils(this); private Object m_body; //////////////////////////////////////////////////////////////////////////// // // IDevModeBridge // //////////////////////////////////////////////////////////////////////////// private final IDevModeBridge m_devModeBridge = new IDevModeBridge() { public ClassLoader getDevClassLoader() { return m_hostModeSupport.getDevClassLoader(); } public Object findJType(String name) { return m_hostModeSupport.findJType(name); } public void invalidateRebind(String binderClassName) { m_hostModeSupport.invalidateRebind(binderClassName); } }; //////////////////////////////////////////////////////////////////////////// // // Constructor // //////////////////////////////////////////////////////////////////////////// public GwtState(ClassLoader parentClassLoader, ModuleDescription moduleDescription) throws Exception { // remember module m_moduleDescription = moduleDescription; if (m_moduleDescription == null) { throw new DesignerException(IExceptionConstants.NO_MODULE_FILE); } // remember arguments m_parentClassLoader = parentClassLoader; m_javaProject = JavaCore.create(m_moduleDescription.getProject()); // remember for access from other classes INSTANCES.add(this); m_testQualifiedName = findTestQualifiedName(); // safe operation m_version = Utils.getVersion(m_javaProject); } /** * Prepares module, HTML and CSS information, then initializes {@link IHostedModeSupport}. */ public void initialize() throws Exception { // prepare module { m_moduleId = m_moduleDescription.getId(); m_moduleName = Utils.readModule(m_moduleDescription).getName(); } // prepare HTML text { InputStream is = GwtState.class.getResourceAsStream(START_HTML); if (is == null) { throw new RuntimeException("Unable to load initialization page."); } try { m_html = IOUtils2.readString(is); } finally { IOUtils.closeQuietly(is); } // add "docType" { String docType = Utils.getDocType(m_moduleDescription); // null means no HTML, defaulting to strict mode if (docType == null) { m_strictMode = true; m_html = "<!doctype html>\n" + m_html; } else { m_strictMode = docType.equalsIgnoreCase("<!doctype html>") || docType.equalsIgnoreCase("<!doctype html PUBLIC \"-//W3C//DTD HTML 4.01//EN\">") || docType.equalsIgnoreCase( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"); if (!StringUtils.isEmpty(docType)) { m_html = docType + "\n" + m_html; } } } // set any declarations { String declarations = getDeclarations(); m_html = StringUtils.replace(m_html, "%CSS_DECLARATIONS%", declarations); } // set inline variables { m_html = StringUtils.replace(m_html, "%MODULE_ID%", m_moduleId); m_html = StringUtils.replace(m_html, "%MODULE_NAME%", m_moduleName); m_html = StringUtils.replace(m_html, "%MODULE_BASE%", m_moduleBaseURL); m_html = StringUtils.replace(m_html, "%GWT_VERSION%", m_version.getStringMajorMinor()); } // set default "locale" { String defaultLocale = Utils.getDefaultLocale(m_moduleDescription); m_html = StringUtils.replace(m_html, "%GWT_LOCALE%", defaultLocale); } // updates HTML file to support CSS files reloading m_html = m_cssSupport.addReloadingFeature(m_html); } // install resource provider HttpServer.getInstance().addResourceProvider(m_moduleBaseURL, new ResourceProvider()); // perform initialize (long running operation) { IProgressMonitor monitor = IDesignPageSite.Helper.getProgressMonitor(); initialize0(monitor); } // set active activate(); } /** * Extracts from stack trace name of class and method of test which creates this {@link GwtState}. */ private static String findTestQualifiedName() { for (StackTraceElement element : Thread.currentThread().getStackTrace()) { String methodName = element.getMethodName(); if (methodName.startsWith("test_")) { return element.getClassName() + "." + methodName; } } return "noTestMethod"; } /** * Initializes {@link IHostedModeSupport} and this {@link GwtState} class. */ private void initialize0(IProgressMonitor monitor) throws Exception { monitor.subTask("Initializing GWT Development Mode..."); m_hostModeSupport = getHostedModeSupport(); { // get shell m_shell = m_hostModeSupport.getBrowserShell(); // set shell size m_shell.setSize(450, 300); } { // prepare user-agent m_html = StringUtils.replace(m_html, "%USER_AGENT%", m_shell.getUserAgentString()); m_html = StringUtils.replace(m_html, "%PROPERTY_PROVIDER_SCRIPTS%", getPropertyProviderValuesScript()); m_html = StringUtils.replace(m_html, "%GWT_isBrowserExplorer%", "" + isBrowserExplorer()); } // prepare hosted mode m_hostModeSupport.startup(getBrowserStartupUrl(), m_moduleId, monitor, getHostedModeTimeout()); m_initialized = true; // configure Window m_body = m_uiObjectUtils.getRootPanelElement(); ReflectionUtils.invokeMethod(m_uiObjectUtils.getClassOfWindow(), "enableScrolling(boolean)", false); } /** * @return the script for assigning property values into "values" map, declared in "__start.html". */ private String getPropertyProviderValuesScript() throws Exception { final StringBuilder sb = new StringBuilder(); ModuleVisitor.accept(m_moduleDescription, new ModuleVisitor() { @Override public void endVisitModule(ModuleElement module) { for (PropertyProviderElement provider : module.getPropertyProviderElements()) { String script = provider.getScript(); if (script != null) { sb.append("values['" + provider.getName() + "'] = function() {" + script + "} ();\n"); } } } }); return sb.toString(); } /** * @return the timeout to wait for hosted mode to initialize. */ private static int getHostedModeTimeout() { IPreferenceStore store = Activator.getStore(); int timeout = store.getInt(Constants.P_GWT_HOSTED_INIT_TIME); if (timeout == 0) { return Integer.MAX_VALUE; } return timeout * 1000; } //////////////////////////////////////////////////////////////////////////// // // Browser support methods // //////////////////////////////////////////////////////////////////////////// /** * Creates a screenshot image of Browser control. This method waits for any pending images to load * and CSS loading Browser operations to complete, then calls native part to create the image. */ public Image createBrowserScreenshot() throws Exception { // wait for possibly updated CSS files to be applied m_cssSupport.waitFor(); // waiting for browser to download all images waitForImages(); // do screen shot return m_shell.createBrowserScreenshot(); } /** * Forces an outstanding messages to be processed */ public void runMessagesLoop() { Runnable enableEventsRunnable = disableMouseAndKeyboard(); try { while (Display.getCurrent().readAndDispatch()) { // wait } } catch (Throwable e) { } finally { enableEventsRunnable.run(); } } /** * We should process messages while waiting Browser to load all images, style, etc. However this * means that user may perform some action, such as trying to change properties, move components, * etc. During execution of command. So, we should catch dangerous events and ignore them. * <p> * http://fogbugz.instantiations.com/fogbugz/default.php?43606 */ private Runnable disableMouseAndKeyboard() { final int[] events = { SWT.MouseDown, SWT.MouseUp, SWT.MouseDoubleClick, SWT.KeyDown, SWT.KeyUp }; final Display display = DesignerPlugin.getStandardDisplay(); final Listener listener = new Listener() { public void handleEvent(Event event) { event.doit = false; event.type = SWT.NONE; } }; for (int i = 0; i < events.length; i++) { display.addFilter(events[i], listener); } return new Runnable() { public void run() { for (int i = 0; i < events.length; i++) { display.removeFilter(events[i], listener); } } }; } //////////////////////////////////////////////////////////////////////////// // // Access // //////////////////////////////////////////////////////////////////////////// /** * @return the internal {@link IHostedModeSupport}. */ IHostedModeSupport getHostModeSupport() { return m_hostModeSupport; } /** * @return the [ERROR] entries passed into GWT log, as string. Returns "<none>" if no such * messages. Only entries of last disposed {@link GwtState} are returned, because this is * what we need during exception rewriting. */ public static String getLoggerErrorMessages() { return m_loggerErrorMessages; } /** * @return the {@link UIObjectUtils} to work with <code>UIObject</code>. */ public UIObjectUtils getUIObjectUtils() { return m_uiObjectUtils; } /** * @return the {@link DOMUtils} to work with <code>Element</code>. */ public DOMUtils getDomUtils() { return m_domUtils; } public IBrowserShell getShell() { return m_shell; } public IDevModeBridge getDevModeBridge() { return m_devModeBridge; } /** * @return the string to set as browser start URL. */ private String getBrowserStartupUrl() { return "http://" + HttpServer.getInstance().getTCPAddress() + m_startHtmlUrl; } /** * @return the {@link ModuleDescription}. */ public ModuleDescription getModuleDescription() { return m_moduleDescription; } public String getModuleName() { return m_moduleId; } public Version getVersion() { return m_version; } /** * @return <code>true</code> if "strict" mode is using, so for example CSS tricks work as * expected. */ public boolean isStrictMode() { return m_strictMode; } /** * @return <code>true</code> if browser is the "Internet Explorer". */ public boolean isBrowserExplorer() { String agent = m_shell.getUserAgentString(); return "ie6".equals(agent) || "ie7".equals(agent) || "ie8".equals(agent) || "ie9".equals(agent); } /** * @return <code>true</code> if browser is based on WebKit. */ public boolean isBrowserWebKit() { String agent = m_shell.getUserAgentString(); return "safari".equals(agent); } /** * @return the {@link CssSupport} for CSS operations. */ public CssSupport getCssSupport() { return m_cssSupport; } //////////////////////////////////////////////////////////////////////////// // // SWT Shell wrapping methods // //////////////////////////////////////////////////////////////////////////// /** * Create platform-dependent shell with browser. * * @return IBrowserShell instance */ public void showShell() { m_shell.showAsPreview(); } //////////////////////////////////////////////////////////////////////////// // // Images // //////////////////////////////////////////////////////////////////////////// /** * When we use images, browser requests images in background, so we should wait until all (local) * images are loaded before making screen shot. Note: waits no more than 500ms. */ private void waitForImages() throws Exception { // System.out.println("*** start IMAGE wait"); long startWait = System.currentTimeMillis(); while (true) { boolean complete = m_hostModeSupport.invokeNativeBoolean("__waitForImages", ArrayUtils.EMPTY_CLASS_ARRAY, ArrayUtils.EMPTY_OBJECT_ARRAY); if (complete) { break; } // do not wait more than 500ms if (System.currentTimeMillis() - startWait > 500) { break; } // wait more runMessagesLoop(); } // System.out.println("*** waiting for IMAGE done in " + (System.currentTimeMillis() - startWait) + "ms"); } //////////////////////////////////////////////////////////////////////////// // // CSS // //////////////////////////////////////////////////////////////////////////// /** * Prepares declarations (CSS, Script & etc) that should be placed in HTML template. Also * remembers used CSS files to check them later for update. */ private String getDeclarations() throws Exception { List<String> declarations = Lists.newArrayList(); // prepare CSS declarations { m_cssSupport.prepareResources(); m_cssSupport.addLinkDeclarations(declarations); } // other declarations { List<IModuleInitializer> initializers = ExternalFactoriesHelper.getElementsInstances( IModuleInitializer.class, "com.google.gdt.eclipse.designer.moduleInitializers", "initializer"); for (IModuleInitializer moduleInitializer : initializers) { moduleInitializer.configure(m_moduleDescription, declarations); } } // final result return StringUtils.join(declarations, "\n"); } //////////////////////////////////////////////////////////////////////////// // // Sharing // //////////////////////////////////////////////////////////////////////////// private boolean m_shared; /** * @return <code>true</code> if this {@link GwtState} is shared, to speed up testing. */ public boolean isShared() { return m_shared; } /** * Marks if this {@link GwtState} is shared or not. */ public void setShared(boolean shared) { m_shared = shared; } //////////////////////////////////////////////////////////////////////////// // // Life cycle // //////////////////////////////////////////////////////////////////////////// /** * @return <code>true</code> if this GWT session was already disposed. */ public boolean isDisposed() { return m_shell == null || m_shell.isDisposed(); } /** * Disposes any resources associated with this GWT session. */ public void dispose() { // don't dispose if shared if (m_shared) { return; } // remember errors if (m_hostModeSupport != null) { m_loggerErrorMessages = m_hostModeSupport.getLogSupport().getErrorMessages(); } else { m_loggerErrorMessages = "No hosted mode."; } // try to dispose if (!isDisposed()) { ExecutionUtils.runLog(new RunnableEx() { public void run() throws Exception { disposeWindowClass(); HttpServer.getInstance().removeResourceProvider(m_moduleBaseURL); m_hostModeSupport.dispose(); } }); } // disposed in any case INSTANCES.remove(this); } /** * Disposes top level GWT <code>Window</code> class. */ private void disposeWindowClass() throws Exception { if (!m_initialized) { return; } // outstanding dispatch events spawned just after the browser shell is disposed. // the workaround is to call onClosed event handler before disposing and... Class<?> classOfWindow = m_uiObjectUtils.getClassOfWindow(); ReflectionUtils.invokeMethod(classOfWindow, "onClosed()"); // prevent fire again // < 1.6 way { // used Vector class prior to 1.4 and ArrayList class for 1.4, // so use reflection to invoke 'clear()' Field closingListenersField = ReflectionUtils.getFieldByName(classOfWindow, "closingListeners"); if (closingListenersField != null) { Object closingListeners = ReflectionUtils.getFieldObject(classOfWindow, "closingListeners"); // ...clear listeners ReflectionUtils.invokeMethod(closingListeners, "clear()"); } } // 1.6 way: disable listeners fire { Field handlersInitedField = ReflectionUtils.getFieldByName(classOfWindow, "closeHandlersInitialized"); if (handlersInitedField != null) { ReflectionUtils.setField(classOfWindow, "closeHandlersInitialized", false); } } // remove window listeners to prevent events firing when the editor closed m_hostModeSupport.invokeNativeVoid("__wbp_cleanupEvents", ArrayUtils.EMPTY_CLASS_ARRAY, ArrayUtils.EMPTY_OBJECT_ARRAY); } /** * Invoked when the context changed (ex., editor switched). */ public void activate() throws Exception { m_hostModeSupport.activate(); } //////////////////////////////////////////////////////////////////////////// // // Modify check // //////////////////////////////////////////////////////////////////////////// /** * Checks if some external files related with this GWT state where modified. For example we check * CSS files. */ public boolean isModified() { return m_cssSupport.isModified(); } //////////////////////////////////////////////////////////////////////////// // // Class loader // //////////////////////////////////////////////////////////////////////////// private IResourcesProvider m_resourcesProvider; public ClassLoader getClassLoader() { return m_hostModeSupport.getClassLoader(); } public IResourcesProvider getResourcesProvider() throws Exception { if (m_resourcesProvider == null) { m_resourcesProvider = m_moduleDescription.getResourcesProvider(); } return m_resourcesProvider; } //////////////////////////////////////////////////////////////////////////// // // Coordinates // //////////////////////////////////////////////////////////////////////////// /** * @return the bounds of <code>Element</code> such that using them for * <code>AbsolutePanel.setWidgetPosition()</code> will place this element/widget into same * location. */ public Rectangle getModelBounds(Object element) { if (element == null) { return new Rectangle(); } Dimension size = getUIObjectSize(element); // for BODY we assume (0,0) as top-left if (isBody(element)) { return new Rectangle(new Point(0, 0), size); } // for any inner element { Insets margins = getMargins(element); int x = m_domUtils.getIntAttribute(element, "offsetLeft") - margins.left; int y = m_domUtils.getIntAttribute(element, "offsetTop") - margins.top; return new Rectangle(x, y, size.width + margins.getWidth(), size.height + margins.getHeight()); } } /** * Returns absolute bounds for given element. Meaning of "absolute" is following: relative to * point (0,0) of screen shot that we show on design canvas. These bounds include also margins of * element. */ public Rectangle getAbsoluteBounds(Object element) { if (element == null) { return new Rectangle(); } Dimension size = getUIObjectSize(element); // for BODY we assume (0,0) as top-left Insets margins = getMargins(element); if (isBody(element)) { int x = 0; int y = 0; if (isStrictMode()) { size.width += margins.getWidth() + getBorders(element).getWidth(); size.height += margins.getHeight() + getBorders(element).getHeight(); } return new Rectangle(new Point(x, y), size); } // for any inner element { int x = m_domUtils.getAbsoluteLeft(element); int y = m_domUtils.getAbsoluteTop(element); // apply margins { x -= margins.left; y -= margins.top; size.width += margins.getWidth(); size.height += margins.getHeight(); } // bounds Rectangle return new Rectangle(x, y, size.width, size.height); } } /** * @return <code>true</code> if the given element represents BODY element. */ public boolean isBody(Object element) { return element == m_body; } /** * @return the size of given element. */ private Dimension getUIObjectSize(Object element) { int width; int height; if (isBody(element)) { if (isBrowserExplorer()) { // Kosta_20080728: at least in GWT 1.5 and IE6 we have to use "offsetXXX" even for BODY, // because in other case we don't see full borders, see "Border for GWT browser" in GMail width = m_domUtils.getIntAttribute(element, "offsetWidth"); height = m_domUtils.getIntAttribute(element, "offsetHeight"); } else { // the size of RootPanel should be fetched from // "clientWidth/clientHeight" attributes because by standards // using "offsetXXX" attributes we get sizes only for BODY element // (Mozilla, IE in DOCTYPE mode) // see http://www.quirksmode.org/js/doctypes.html for details width = m_domUtils.getIntAttribute(element, "clientWidth"); height = m_domUtils.getIntAttribute(element, "clientHeight"); } } else { width = m_domUtils.getIntAttribute(element, "offsetWidth"); height = m_domUtils.getIntAttribute(element, "offsetHeight"); } return new Dimension(width, height); } public Insets getBorders(Object element) { int top = getBorderSideWidth(element, "top"); int left = getBorderSideWidth(element, "left"); int bottom = getBorderSideWidth(element, "bottom"); int right = getBorderSideWidth(element, "right"); return new Insets(top, left, bottom, right); } private int getBorderSideWidth(Object element, String name) { String style = getComputedStyle(element, "border-" + name + "-style"); if (style == null || "none".equals(style)) { return 0; } return getComputedStylePx(element, "border-" + name + "-width"); } public Insets getMargins(Object element) { String oldDisplayStyleValue = null; try { if (isBrowserWebKit()) { // Bug/Feature in WebKit: if the position of the element is // not absolute and there is a free space right to the element // then this space added to element's space as 'margin-right' computed style value. // The workaround is to set 'display' style to 'none' while measuring margins. // Refs: // http://fogbugz.instantiations.com/fogbugz/default.asp?45380 // https://bugs.webkit.org/show_bug.cgi?id=13343 Object parent = m_domUtils.getParent(element); String parentTag = m_domUtils.getTagName(parent); if (!"TD".equals(parentTag)) { // This workaround causes problem with "top" position of the element in "TD" - it // gets shifted by some value, something like half of TD height. Probably because of // using the default "center" vertical alignment. So, we should not touch children of TD. oldDisplayStyleValue = m_domUtils.getStyleAttribute(element, "display"); m_domUtils.setStyleAttribute(element, "display", "none"); } } int top = getComputedStylePx(element, "margin-top"); int left = getComputedStylePx(element, "margin-left"); int bottom = getComputedStylePx(element, "margin-bottom"); int right = getComputedStylePx(element, "margin-right"); return new Insets(top, left, bottom, right); } finally { if (oldDisplayStyleValue != null) { // restore display style m_domUtils.setStyleAttribute(element, "display", oldDisplayStyleValue); } } } public Insets getPaddings(Object element) { int top = getComputedStylePx(element, "padding-top"); int left = getComputedStylePx(element, "padding-left"); int bottom = getComputedStylePx(element, "padding-bottom"); int right = getComputedStylePx(element, "padding-right"); return new Insets(top, left, bottom, right); } //////////////////////////////////////////////////////////////////////////// // // Style // //////////////////////////////////////////////////////////////////////////// /** * @return the attribute of computed style. */ public String getComputedStyle(Object element, String style) { return m_hostModeSupport.invokeNativeString("__getStyle", new Class[] { m_uiObjectUtils.getClassOfElement(), String.class }, new Object[] { element, style }); } /** * @return the value of integer attribute of computed style. */ private int getComputedStylePx(Object element, String style) { String styleString = getComputedStyle(element, style); return getValuePx(styleString); } /** * @return the number of pixels from given size style string. */ public static int getValuePx(String styleString) { if (styleString != null && styleString.endsWith("px") /*"0px"*/) { styleString = StringUtils.removeEnd(styleString, "px"); try { return (int) Double.parseDouble(styleString); } catch (NumberFormatException e) { return 0; } } // no style set or browser can't return it for designer return 0; } //////////////////////////////////////////////////////////////////////////// // // Visiting // //////////////////////////////////////////////////////////////////////////// /** * Visits public folders of given module and inherited modules (recursively). */ public void accept(ModuleVisitor visitor) throws Exception { ModuleVisitor.accept(m_moduleDescription, visitor); } //////////////////////////////////////////////////////////////////////////// // // RequestHandler // //////////////////////////////////////////////////////////////////////////// private class ResourceProvider implements IResourceProvider { /** * Returns public resource with given path. * * Here "public" means resource placed in folders defined as public in module descriptors. */ public byte[] getResource(String requestPath) { String resourcePath = StringUtils.substringBefore(requestPath, "?"); // System.out.println(System.currentTimeMillis() + ": requestPath: " + requestPath); // resources from classpath { int index = requestPath.indexOf(CLASSPATH_URL_MARKER); if (index != -1) { String classpathPath = requestPath.substring(index + CLASSPATH_URL_MARKER.length()); try { return IOUtils2.readBytes(getResourcesProvider().getResourceAsStream(classpathPath)); } catch (Throwable e) { return null; } } } // HTML if (m_startHtmlUrl.equals(resourcePath)) { return m_html.getBytes(); } // prepare "public" resource path String publicResourcePath = StringUtils.removeStart(resourcePath, m_moduleBaseURL); /*synchronized (System.out) { System.out.println("publicResourcePath: " + publicResourcePath); System.out.flush(); }*/ // may be CSS "apply wait" found { byte[] result = m_cssSupport.getResourceWait(publicResourcePath); if (result != null) { return result; } } // load resource try { byte[] result = null; // load static resource { InputStream is = Utils.getResource(m_moduleDescription, publicResourcePath); if (is != null) { result = IOUtils2.readBytes(is); } } // may be generated resource if (result == null) { result = m_hostModeSupport.getGeneratedResource(publicResourcePath); } // may be no resource if (result == null) { return null; } // if CSS resource, then include "apply wait" class result = m_cssSupport.getResource(publicResourcePath, result); // done //System.out.println("-----------: " + result.length); return result; } catch (Throwable e) { throw ReflectionUtils.propagate(e); } } } //////////////////////////////////////////////////////////////////////////// // // IHostedModeSupportFactory // //////////////////////////////////////////////////////////////////////////// private static final String HOSTED_MODE_SUPPORT_FACTORIES_POINT = "com.google.gdt.eclipse.designer.hosted.hostedModeFactory"; private static List<IHostedModeSupportFactory> getHostedModeSupportFactories() { return ExternalFactoriesHelper.getElementsInstances(IHostedModeSupportFactory.class, HOSTED_MODE_SUPPORT_FACTORIES_POINT, "factory"); } private IHostedModeSupport getHostedModeSupport() throws Exception { String versionString = m_version.getStringMajorMinor(); // prepare factories List<IHostedModeSupportFactory> supportFactories = getHostedModeSupportFactories(); if (supportFactories.isEmpty()) { throw new DesignerException(IExceptionConstants.NO_GWT_SDK_SUPPORT); } // ask each factory for (IHostedModeSupportFactory supportFactory : supportFactories) { IHostedModeSupport hostedModeSupport = supportFactory.create(versionString, m_parentClassLoader, m_moduleDescription); if (hostedModeSupport != null) { return hostedModeSupport; } } throw new DesignerException(IExceptionConstants.UNSUPPORTED_GWT_SDK, versionString); } }