From 72d9cc9ec098952dfdb03708f808da555307e78d Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Mon, 20 Aug 2012 19:19:47 +0300 Subject: Add RootProvider for Root selection without custom Application (#8159) --- server/src/com/vaadin/Application.java | 70 ++++++++-------------- .../com/vaadin/terminal/AbstractRootProvider.java | 35 +++++++++++ .../com/vaadin/terminal/DefaultRootProvider.java | 51 ++++++++++++++++ server/src/com/vaadin/terminal/RootProvider.java | 29 +++++++++ .../terminal/gwt/server/ApplicationServlet.java | 2 + .../component/root/CustomRootClassLoader.java | 18 ++++-- .../vaadin/launcher/ApplicationRunnerServlet.java | 33 +++++----- .../tests/application/RefreshStatePreserve.java | 16 +++-- .../tests/components/root/RootsInMultipleTabs.java | 15 ++++- 9 files changed, 191 insertions(+), 78 deletions(-) create mode 100644 server/src/com/vaadin/terminal/AbstractRootProvider.java create mode 100644 server/src/com/vaadin/terminal/DefaultRootProvider.java create mode 100644 server/src/com/vaadin/terminal/RootProvider.java diff --git a/server/src/com/vaadin/Application.java b/server/src/com/vaadin/Application.java index b120c8455a..d2924eb716 100644 --- a/server/src/com/vaadin/Application.java +++ b/server/src/com/vaadin/Application.java @@ -32,6 +32,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.LinkedList; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; @@ -56,6 +57,7 @@ import com.vaadin.terminal.ApplicationResource; import com.vaadin.terminal.CombinedRequest; import com.vaadin.terminal.DeploymentConfiguration; import com.vaadin.terminal.RequestHandler; +import com.vaadin.terminal.RootProvider; import com.vaadin.terminal.Terminal; import com.vaadin.terminal.VariableOwner; import com.vaadin.terminal.WrappedRequest; @@ -503,6 +505,8 @@ public class Application implements Terminal.ErrorListener, Serializable { */ private Set initedRoots = new HashSet(); + private List rootProviders = new LinkedList(); + /** * Gets the user of the application. * @@ -1873,55 +1877,21 @@ public class Application implements Terminal.ErrorListener, Serializable { */ protected Root getRoot(WrappedRequest request) throws RootRequiresMoreInformationException { - String rootClassName = getRootClassName(request); - try { - ClassLoader classLoader = request.getDeploymentConfiguration() - .getClassLoader(); - if (classLoader == null) { - classLoader = getClass().getClassLoader(); - } - Class rootClass = Class.forName(rootClassName, - true, classLoader).asSubclass(Root.class); - try { - Root root = rootClass.newInstance(); - return root; - } catch (Exception e) { - throw new RuntimeException("Could not instantiate root class " - + rootClassName, e); + + // Iterate in reverse order - test check newest provider first + for (int i = rootProviders.size() - 1; i >= 0; i--) { + RootProvider provider = rootProviders.get(i); + + Class rootClass = provider.getRootClass(this, + request); + + if (rootClass != null) { + return provider.instantiateRoot(this, rootClass, request); } - } catch (ClassNotFoundException e) { - throw new RuntimeException("Could not load root class " - + rootClassName, e); } - } - /** - * Provides the name of the Root class that should be used for - * a request. The class must have an accessible no-args constructor. - *

- * The default implementation uses the {@value #ROOT_PARAMETER} parameter - * from web.xml. - *

- *

- * This method is mainly used by the default implementation of - * {@link #getRoot(WrappedRequest)}. If you override that method with your - * own functionality, the results of this method might not be used. - *

- * - * @param request - * the request for which a new root is required - * @return the name of the root class to use - * - * @since 7.0 - */ - protected String getRootClassName(WrappedRequest request) { - Object rootClassNameObj = getProperties().get(ROOT_PARAMETER); - if (rootClassNameObj instanceof String) { - return (String) rootClassNameObj; - } else { - throw new RuntimeException("No " + ROOT_PARAMETER - + " defined in web.xml"); - } + throw new RuntimeException( + "No root providers available or providers are not able to find root instance"); } /** @@ -2169,6 +2139,14 @@ public class Application implements Terminal.ErrorListener, Serializable { return configuration.isProductionMode(); } + public void addRootProvider(RootProvider rootProvider) { + rootProviders.add(rootProvider); + } + + public void removeRootProvider(RootProvider rootProvider) { + rootProviders.remove(rootProvider); + } + /** * Finds the {@link Root} to which a particular request belongs. If the * request originates from an existing Root, that root is returned. In other diff --git a/server/src/com/vaadin/terminal/AbstractRootProvider.java b/server/src/com/vaadin/terminal/AbstractRootProvider.java new file mode 100644 index 0000000000..0b63003440 --- /dev/null +++ b/server/src/com/vaadin/terminal/AbstractRootProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright 2011 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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.vaadin.terminal; + +import com.vaadin.Application; +import com.vaadin.ui.Root; + +public abstract class AbstractRootProvider implements RootProvider { + + @Override + public Root instantiateRoot(Application application, + Class type, WrappedRequest request) { + try { + return type.newInstance(); + } catch (InstantiationException e) { + throw new RuntimeException("Could not instantiate root class", e); + } catch (IllegalAccessException e) { + throw new RuntimeException("Could not access root class", e); + } + } +} diff --git a/server/src/com/vaadin/terminal/DefaultRootProvider.java b/server/src/com/vaadin/terminal/DefaultRootProvider.java new file mode 100644 index 0000000000..cbf8c98828 --- /dev/null +++ b/server/src/com/vaadin/terminal/DefaultRootProvider.java @@ -0,0 +1,51 @@ +/* + * Copyright 2011 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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.vaadin.terminal; + +import com.vaadin.Application; +import com.vaadin.RootRequiresMoreInformationException; +import com.vaadin.ui.Root; + +public class DefaultRootProvider extends AbstractRootProvider { + + @Override + public Class getRootClass(Application application, + WrappedRequest request) throws RootRequiresMoreInformationException { + Object rootClassNameObj = application + .getProperty(Application.ROOT_PARAMETER); + + if (rootClassNameObj instanceof String) { + String rootClassName = rootClassNameObj.toString(); + + ClassLoader classLoader = request.getDeploymentConfiguration() + .getClassLoader(); + if (classLoader == null) { + classLoader = getClass().getClassLoader(); + } + try { + Class rootClass = Class.forName(rootClassName, + true, classLoader).asSubclass(Root.class); + + return rootClass; + } catch (ClassNotFoundException e) { + throw new RuntimeException("Could not find root class", e); + } + } + + return null; + } +} diff --git a/server/src/com/vaadin/terminal/RootProvider.java b/server/src/com/vaadin/terminal/RootProvider.java new file mode 100644 index 0000000000..476cf1bd78 --- /dev/null +++ b/server/src/com/vaadin/terminal/RootProvider.java @@ -0,0 +1,29 @@ +/* + * Copyright 2011 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 + * + * 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.vaadin.terminal; + +import com.vaadin.Application; +import com.vaadin.RootRequiresMoreInformationException; +import com.vaadin.ui.Root; + +public interface RootProvider { + public Class getRootClass(Application application, + WrappedRequest request) throws RootRequiresMoreInformationException; + + public Root instantiateRoot(Application application, + Class type, WrappedRequest request); +} diff --git a/server/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java b/server/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java index 06bc70872d..52885f3fbb 100644 --- a/server/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java +++ b/server/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java @@ -20,6 +20,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import com.vaadin.Application; +import com.vaadin.terminal.DefaultRootProvider; import com.vaadin.terminal.gwt.server.ServletPortletHelper.ApplicationClassException; /** @@ -69,6 +70,7 @@ public class ApplicationServlet extends AbstractApplicationServlet { // Creates a new application instance try { final Application application = getApplicationClass().newInstance(); + application.addRootProvider(new DefaultRootProvider()); return application; } catch (final IllegalAccessException e) { diff --git a/tests/server-side/com/vaadin/tests/server/component/root/CustomRootClassLoader.java b/tests/server-side/com/vaadin/tests/server/component/root/CustomRootClassLoader.java index fa730515a2..74770f8652 100644 --- a/tests/server-side/com/vaadin/tests/server/component/root/CustomRootClassLoader.java +++ b/tests/server-side/com/vaadin/tests/server/component/root/CustomRootClassLoader.java @@ -6,15 +6,16 @@ import java.util.Properties; import junit.framework.TestCase; +import org.easymock.EasyMock; + import com.vaadin.Application; import com.vaadin.Application.ApplicationStartEvent; import com.vaadin.RootRequiresMoreInformationException; +import com.vaadin.terminal.DefaultRootProvider; import com.vaadin.terminal.DeploymentConfiguration; import com.vaadin.terminal.WrappedRequest; import com.vaadin.ui.Root; -import org.easymock.EasyMock; - public class CustomRootClassLoader extends TestCase { /** @@ -111,10 +112,17 @@ public class CustomRootClassLoader extends TestCase { private Application createStubApplication() { return new Application() { + { + addRootProvider(new DefaultRootProvider()); + } + @Override - protected String getRootClassName(WrappedRequest request) { - // Always use the same root class - return MyRoot.class.getName(); + public String getProperty(String name) { + if (name.equals(ROOT_PARAMETER)) { + return MyRoot.class.getName(); + } else { + return super.getProperty(name); + } } @Override diff --git a/tests/testbench/com/vaadin/launcher/ApplicationRunnerServlet.java b/tests/testbench/com/vaadin/launcher/ApplicationRunnerServlet.java index 6b7b36c3f3..bb37082d30 100644 --- a/tests/testbench/com/vaadin/launcher/ApplicationRunnerServlet.java +++ b/tests/testbench/com/vaadin/launcher/ApplicationRunnerServlet.java @@ -30,6 +30,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.vaadin.Application; +import com.vaadin.RootRequiresMoreInformationException; +import com.vaadin.terminal.AbstractRootProvider; import com.vaadin.terminal.WrappedRequest; import com.vaadin.terminal.gwt.server.AbstractApplicationServlet; import com.vaadin.terminal.gwt.server.WrappedHttpServletRequest; @@ -39,23 +41,6 @@ import com.vaadin.ui.Root; @SuppressWarnings("serial") public class ApplicationRunnerServlet extends AbstractApplicationServlet { - /** - * Internal implementation of an application with a dynamically selected - * Root implementation; - */ - private static class RootRunnerApplication extends Application { - private final Class runnableClass; - - private RootRunnerApplication(Class runnableClass) { - this.runnableClass = runnableClass; - } - - @Override - protected String getRootClassName(WrappedRequest request) { - return runnableClass.getCanonicalName(); - } - } - /** * The name of the application class currently used. Only valid within one * request. @@ -126,7 +111,17 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet { try { final Class classToRun = getClassToRun(); if (Root.class.isAssignableFrom(classToRun)) { - return new RootRunnerApplication(classToRun); + Application application = new Application(); + application.addRootProvider(new AbstractRootProvider() { + + @Override + public Class getRootClass( + Application application, WrappedRequest request) + throws RootRequiresMoreInformationException { + return (Class) classToRun; + } + }); + return application; } else if (Application.class.isAssignableFrom(classToRun)) { return (Application) classToRun.newInstance(); } else { @@ -221,7 +216,7 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet { throws ClassNotFoundException { Class classToRun = getClassToRun(); if (Root.class.isAssignableFrom(classToRun)) { - return RootRunnerApplication.class; + return Application.class; } else if (Application.class.isAssignableFrom(classToRun)) { return classToRun.asSubclass(Application.class); } else { diff --git a/tests/testbench/com/vaadin/tests/application/RefreshStatePreserve.java b/tests/testbench/com/vaadin/tests/application/RefreshStatePreserve.java index 36a793bd6d..bd2aea3756 100644 --- a/tests/testbench/com/vaadin/tests/application/RefreshStatePreserve.java +++ b/tests/testbench/com/vaadin/tests/application/RefreshStatePreserve.java @@ -1,5 +1,8 @@ package com.vaadin.tests.application; +import com.vaadin.Application; +import com.vaadin.RootRequiresMoreInformationException; +import com.vaadin.terminal.AbstractRootProvider; import com.vaadin.terminal.WrappedRequest; import com.vaadin.tests.components.AbstractTestApplication; import com.vaadin.ui.Label; @@ -20,11 +23,14 @@ public class RefreshStatePreserve extends AbstractTestApplication { public void init() { super.init(); setRootPreserved(true); - } - - @Override - protected String getRootClassName(WrappedRequest request) { - return RefreshStateRoot.class.getName(); + addRootProvider(new AbstractRootProvider() { + @Override + public Class getRootClass(Application application, + WrappedRequest request) + throws RootRequiresMoreInformationException { + return RefreshStateRoot.class; + } + }); } @Override diff --git a/tests/testbench/com/vaadin/tests/components/root/RootsInMultipleTabs.java b/tests/testbench/com/vaadin/tests/components/root/RootsInMultipleTabs.java index c3b20c5e7c..ae3182401d 100644 --- a/tests/testbench/com/vaadin/tests/components/root/RootsInMultipleTabs.java +++ b/tests/testbench/com/vaadin/tests/components/root/RootsInMultipleTabs.java @@ -1,5 +1,8 @@ package com.vaadin.tests.components.root; +import com.vaadin.Application; +import com.vaadin.RootRequiresMoreInformationException; +import com.vaadin.terminal.AbstractRootProvider; import com.vaadin.terminal.WrappedRequest; import com.vaadin.tests.components.AbstractTestApplication; import com.vaadin.ui.Label; @@ -19,9 +22,15 @@ public class RootsInMultipleTabs extends AbstractTestApplication { } } - @Override - protected String getRootClassName(WrappedRequest request) { - return TabRoot.class.getName(); + public RootsInMultipleTabs() { + addRootProvider(new AbstractRootProvider() { + @Override + public Class getRootClass(Application application, + WrappedRequest request) + throws RootRequiresMoreInformationException { + return TabRoot.class; + } + }); } @Override -- cgit v1.2.3