import java.io.File;
import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collections;
import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import com.vaadin.launcher.CustomDeploymentConfiguration.Conf;
+import com.vaadin.server.DefaultDeploymentConfiguration;
+import com.vaadin.server.DeploymentConfiguration;
import com.vaadin.server.LegacyApplication;
import com.vaadin.server.LegacyVaadinServlet;
import com.vaadin.server.ServiceException;
import com.vaadin.server.VaadinSession;
import com.vaadin.tests.components.TestBase;
import com.vaadin.ui.UI;
+import com.vaadin.util.CurrentInstance;
@SuppressWarnings("serial")
public class ApplicationRunnerServlet extends LegacyVaadinServlet {
return Logger.getLogger(ApplicationRunnerServlet.class.getName());
}
+ @Override
+ protected DeploymentConfiguration createDeploymentConfiguration(
+ Properties initParameters) {
+ // Get the original configuration from the super class
+ final DeploymentConfiguration originalConfiguration = super
+ .createDeploymentConfiguration(initParameters);
+
+ // And then create a proxy instance that delegates to the original
+ // configuration or a customized version
+ return (DeploymentConfiguration) Proxy.newProxyInstance(
+ DeploymentConfiguration.class.getClassLoader(),
+ new Class[] { DeploymentConfiguration.class },
+ new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method,
+ Object[] args) throws Throwable {
+ if (method.getDeclaringClass() == DeploymentConfiguration.class) {
+ // Find the configuration instance to delegate to
+ DeploymentConfiguration configuration = findDeploymentConfiguration(originalConfiguration);
+
+ return method.invoke(configuration, args);
+ } else {
+ return method.invoke(proxy, args);
+ }
+ }
+ });
+ }
+
+ private DeploymentConfiguration findDeploymentConfiguration(
+ DeploymentConfiguration originalConfiguration) throws Exception {
+ // First level of cache
+ DeploymentConfiguration configuration = CurrentInstance
+ .get(DeploymentConfiguration.class);
+
+ if (configuration == null) {
+ // Not in cache, try to find a VaadinSession to get it from
+ VaadinSession session = VaadinSession.getCurrent();
+
+ if (session == null) {
+ /*
+ * There's no current session, request or response when serving
+ * static resources, but there's still the current request
+ * maintained by AppliationRunnerServlet, and there's most
+ * likely also a HttpSession containing a VaadinSession for that
+ * request.
+ */
+
+ HttpServletRequest currentRequest = request.get();
+ if (currentRequest != null) {
+ HttpSession httpSession = currentRequest.getSession(false);
+ if (httpSession != null) {
+ Map<Class<?>, CurrentInstance> oldCurrent = CurrentInstance
+ .setCurrent((VaadinSession) null);
+ try {
+ session = getService().findVaadinSession(
+ new VaadinServletRequest(currentRequest,
+ getService()));
+ } finally {
+ /*
+ * Clear some state set by findVaadinSession to
+ * avoid accidentally depending on it when coding on
+ * e.g. static request handling.
+ */
+ CurrentInstance.restoreInstances(oldCurrent);
+ currentRequest.removeAttribute(VaadinSession.class
+ .getName());
+ }
+ }
+ }
+ }
+
+ if (session != null) {
+ String name = ApplicationRunnerServlet.class.getName()
+ + ".deploymentConfiguration";
+ try {
+ session.lock();
+ configuration = (DeploymentConfiguration) session
+ .getAttribute(name);
+
+ if (configuration == null) {
+ Class<?> classToRun;
+ try {
+ classToRun = getClassToRun();
+ } catch (ClassNotFoundException e) {
+ /*
+ * This happens e.g. if the UI class defined in the
+ * URL is not found or if this servlet just serves
+ * static resources while there's some other servlet
+ * that serves the UI (e.g. when using /run-push/).
+ */
+ return originalConfiguration;
+ }
+
+ CustomDeploymentConfiguration customDeploymentConfiguration = classToRun
+ .getAnnotation(CustomDeploymentConfiguration.class);
+ if (customDeploymentConfiguration != null) {
+ Properties initParameters = new Properties(
+ originalConfiguration.getInitParameters());
+
+ for (Conf entry : customDeploymentConfiguration
+ .value()) {
+ initParameters.put(entry.name(), entry.value());
+ }
+
+ configuration = new DefaultDeploymentConfiguration(
+ getClass(), initParameters);
+ } else {
+ configuration = originalConfiguration;
+ }
+
+ session.setAttribute(name, configuration);
+ }
+ } finally {
+ session.unlock();
+ }
+
+ CurrentInstance.set(DeploymentConfiguration.class,
+ configuration);
+
+ } else {
+ configuration = originalConfiguration;
+ }
+ }
+ return configuration;
+ }
}
--- /dev/null
+/*
+ * Copyright 2000-2014 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.launcher;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(value = ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CustomDeploymentConfiguration {
+
+ @Target(value = ElementType.TYPE)
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface Conf {
+ public String name();
+
+ public String value();
+ }
+
+ public CustomDeploymentConfiguration.Conf[] value();
+}
--- /dev/null
+/*
+ * Copyright 2000-2014 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.tests.applicationservlet;
+
+import com.vaadin.launcher.ApplicationRunnerServlet;
+import com.vaadin.launcher.CustomDeploymentConfiguration;
+import com.vaadin.launcher.CustomDeploymentConfiguration.Conf;
+import com.vaadin.server.DeploymentConfiguration;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Label;
+
+@CustomDeploymentConfiguration({
+ @Conf(name = "customParam", value = "customValue"),
+ @Conf(name = "resourceCacheTime", value = "3599") })
+public class CustomDeploymentConf extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ DeploymentConfiguration deploymentConfiguration = getSession()
+ .getService().getDeploymentConfiguration();
+ addComponent(new Label("Resource cache time: "
+ + deploymentConfiguration.getResourceCacheTime()));
+ addComponent(new Label("Custom config param: "
+ + deploymentConfiguration.getApplicationOrSystemProperty(
+ "customParam", null)));
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Demonstrates the @"
+ + CustomDeploymentConfiguration.class.getSimpleName()
+ + " feature that allows customizing the effective deployment configuration for test UIs run through "
+ + ApplicationRunnerServlet.class.getSimpleName() + ".";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return Integer.valueOf(14215);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2000-2014 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.tests.applicationservlet;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.testbench.elements.LabelElement;
+import com.vaadin.testbench.elements.VerticalLayoutElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class CustomDeploymentConfTest extends MultiBrowserTest {
+ @Test
+ public void testCustomDeploymentConf() {
+ openTestURL();
+
+ LabelElement cacheTimeLabel = $$(VerticalLayoutElement.class)
+ .$$(VerticalLayoutElement.class).$$(LabelElement.class).first();
+
+ LabelElement customParamLabel = $$(VerticalLayoutElement.class)
+ .$$(VerticalLayoutElement.class).$$(LabelElement.class).get(1);
+
+ Assert.assertEquals("Resource cache time: 3599",
+ cacheTimeLabel.getText());
+ Assert.assertEquals("Custom config param: customValue",
+ customParamLabel.getText());
+ }
+}