@@ -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<Integer> initedRoots = new HashSet<Integer>(); | |||
private List<RootProvider> rootProviders = new LinkedList<RootProvider>(); | |||
/** | |||
* 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<? extends Root> 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<? extends Root> 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 <code>Root</code> class that should be used for | |||
* a request. The class must have an accessible no-args constructor. | |||
* <p> | |||
* The default implementation uses the {@value #ROOT_PARAMETER} parameter | |||
* from web.xml. | |||
* </p> | |||
* <p> | |||
* 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. | |||
* </p> | |||
* | |||
* @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 |
@@ -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<? extends Root> 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); | |||
} | |||
} | |||
} |
@@ -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<? extends Root> 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<? extends Root> 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; | |||
} | |||
} |
@@ -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<? extends Root> getRootClass(Application application, | |||
WrappedRequest request) throws RootRequiresMoreInformationException; | |||
public Root instantiateRoot(Application application, | |||
Class<? extends Root> type, WrappedRequest request); | |||
} |
@@ -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) { |
@@ -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 |
@@ -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<? extends Root> getRootClass( | |||
Application application, WrappedRequest request) | |||
throws RootRequiresMoreInformationException { | |||
return (Class<? extends Root>) 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 { |
@@ -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<? extends Root> getRootClass(Application application, | |||
WrappedRequest request) | |||
throws RootRequiresMoreInformationException { | |||
return RefreshStateRoot.class; | |||
} | |||
}); | |||
} | |||
@Override |
@@ -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<? extends Root> getRootClass(Application application, | |||
WrappedRequest request) | |||
throws RootRequiresMoreInformationException { | |||
return TabRoot.class; | |||
} | |||
}); | |||
} | |||
@Override |