diff options
author | Henri Sara <hesara@vaadin.com> | 2015-09-30 11:29:45 +0300 |
---|---|---|
committer | Henri Sara <hesara@vaadin.com> | 2015-09-30 11:45:53 +0300 |
commit | 7804edf4a9228255cb7857dbd7c17d87ee976f67 (patch) | |
tree | 17f6770bfa8ce5d3d4c889724cbac41c74c336aa | |
parent | 5b4fd9305618581e62c9c8ca4f223a7f82b73600 (diff) | |
download | vaadin-framework-7804edf4a9228255cb7857dbd7c17d87ee976f67.tar.gz vaadin-framework-7804edf4a9228255cb7857dbd7c17d87ee976f67.zip |
Support declarative prefix "vaadin-" (#18957)
This is a backport of 1011cff7e8139cd1b7138b2e538264c755c7482f
with the old default ("v-").
Change-Id: Idafc3a071aeec6d4214e867cc5cd984ae535cb62
6 files changed, 359 insertions, 11 deletions
diff --git a/server/src/com/vaadin/server/Constants.java b/server/src/com/vaadin/server/Constants.java index 5a0d852299..379bfa4f2a 100644 --- a/server/src/com/vaadin/server/Constants.java +++ b/server/src/com/vaadin/server/Constants.java @@ -137,6 +137,7 @@ public interface Constants { static final String SERVLET_PARAMETER_LEGACY_PROPERTY_TOSTRING = "legacyPropertyToString"; static final String SERVLET_PARAMETER_SYNC_ID_CHECK = "syncIdCheck"; static final String SERVLET_PARAMETER_SENDURLSASPARAMETERS = "sendUrlsAsParameters"; + static final String SERVLET_PARAMETER_LEGACY_DESIGN_PREFIX = "legacyDesignPrefix"; // Configurable parameter names static final String PARAMETER_VAADIN_RESOURCES = "Resources"; diff --git a/server/src/com/vaadin/ui/declarative/DesignContext.java b/server/src/com/vaadin/ui/declarative/DesignContext.java index 0d68c22ea0..d660011a58 100644 --- a/server/src/com/vaadin/ui/declarative/DesignContext.java +++ b/server/src/com/vaadin/ui/declarative/DesignContext.java @@ -30,6 +30,9 @@ import org.jsoup.nodes.Element; import org.jsoup.nodes.Node; import com.vaadin.annotations.DesignRoot; +import com.vaadin.server.Constants; +import com.vaadin.server.DeploymentConfiguration; +import com.vaadin.server.VaadinService; import com.vaadin.ui.Component; import com.vaadin.ui.HasComponents; import com.vaadin.ui.declarative.Design.ComponentFactory; @@ -41,11 +44,22 @@ import com.vaadin.ui.declarative.Design.ComponentMapper; * mappings from local ids, global ids and captions to components , as well as a * mapping between prefixes and package names (such as "v" -> "com.vaadin.ui"). * + * Vaadin versions 7.5.7 and later support reading designs with either "v" or + * "vaadin" as the prefix, but only write "v" by default. Writing with the new + * prefix can be activated with value {@code false} for the property or context + * parameter {@link Constants#SERVLET_PARAMETER_LEGACY_DESIGN_PREFIX}. Vaadin + * 7.6 and later will use "vaadin" as the default prefix. + * * @since 7.4 * @author Vaadin Ltd */ public class DesignContext implements Serializable { + private static final String LEGACY_PREFIX = "v"; + private static final String VAADIN_PREFIX = "vaadin"; + + private static final String VAADIN_UI_PACKAGE = "com.vaadin.ui"; + // cache for object instances private static Map<Class<?>, Component> instanceCache = new ConcurrentHashMap<Class<?>, Component>(); @@ -67,23 +81,24 @@ public class DesignContext implements Serializable { // namespace mappings private Map<String, String> packageToPrefix = new HashMap<String, String>(); private Map<String, String> prefixToPackage = new HashMap<String, String>(); - // prefix names for which no package-mapping element will be created in the - // html tree (this includes at least "v" which is always taken to refer - // to "com.vaadin.ui". - private Map<String, String> defaultPrefixes = new HashMap<String, String>(); // component creation listeners private List<ComponentCreationListener> listeners = new ArrayList<ComponentCreationListener>(); private ShouldWriteDataDelegate shouldWriteDataDelegate = ShouldWriteDataDelegate.DEFAULT; + // this cannot be static because of testability issues + private Boolean legacyDesignPrefix = null; + public DesignContext(Document doc) { this.doc = doc; // Initialize the mapping between prefixes and package names. - defaultPrefixes.put("v", "com.vaadin.ui"); - for (String prefix : defaultPrefixes.keySet()) { - String packageName = defaultPrefixes.get(prefix); - addPackagePrefix(prefix, packageName); + if (isLegacyPrefixEnabled()) { + addPackagePrefix(LEGACY_PREFIX, VAADIN_UI_PACKAGE); + prefixToPackage.put(VAADIN_PREFIX, VAADIN_UI_PACKAGE); + } else { + addPackagePrefix(VAADIN_PREFIX, VAADIN_UI_PACKAGE); + prefixToPackage.put(LEGACY_PREFIX, VAADIN_UI_PACKAGE); } } @@ -259,6 +274,11 @@ public class DesignContext implements Serializable { /** * Creates a two-way mapping between a prefix and a package name. * + * Note that modifying the mapping for {@value #VAADIN_UI_PACKAGE} may + * invalidate the backwards compatibility mechanism supporting reading such + * components with either {@value #LEGACY_PREFIX} or {@value #VAADIN_PREFIX} + * as prefix. + * * @param prefix * the prefix name without an ending dash (for instance, "v" is * by default used for "com.vaadin.ui") @@ -288,7 +308,11 @@ public class DesignContext implements Serializable { * registered */ public String getPackagePrefix(String packageName) { - return packageToPrefix.get(packageName); + if (VAADIN_UI_PACKAGE.equals(packageName)) { + return isLegacyPrefixEnabled() ? LEGACY_PREFIX : VAADIN_PREFIX; + } else { + return packageToPrefix.get(packageName); + } } /** @@ -396,7 +420,7 @@ public class DesignContext implements Serializable { for (String prefix : getPackagePrefixes()) { // Only store the prefix-name mapping if it is not a default mapping // (such as "v" -> "com.vaadin.ui") - if (defaultPrefixes.get(prefix) == null) { + if (!VAADIN_PREFIX.equals(prefix) && !LEGACY_PREFIX.equals(prefix)) { Node newNode = doc.createElement("meta"); newNode.attr("name", "package-mapping"); String prefixToPackageName = prefix + ":" + getPackage(prefix); @@ -407,6 +431,31 @@ public class DesignContext implements Serializable { } /** + * Check whether the legacy prefix "v" or the default prefix "vaadin" should + * be used when writing designs. The property or context parameter + * {@link Constants#SERVLET_PARAMETER_LEGACY_DESIGN_PREFIX} can be used to + * switch to the legacy prefix. + * + * @since + * @return true to use the legacy prefix, false by default + */ + protected boolean isLegacyPrefixEnabled() { + if (legacyDesignPrefix != null) { + return legacyDesignPrefix.booleanValue(); + } + if (VaadinService.getCurrent() == null) { + // This will happen at least in JUnit tests. + return true; + } + DeploymentConfiguration configuration = VaadinService.getCurrent() + .getDeploymentConfiguration(); + legacyDesignPrefix = configuration.getApplicationOrSystemProperty( + Constants.SERVLET_PARAMETER_LEGACY_DESIGN_PREFIX, "true") + .equals("true"); + return legacyDesignPrefix.booleanValue(); + } + + /** * Creates an html tree node corresponding to the given element. Also * initializes its attributes by calling writeDesign. As a result of the * writeDesign() call, this method creates the entire subtree rooted at the @@ -511,11 +560,21 @@ public class DesignContext implements Serializable { Component component = componentMapper.tagToComponent(tag, Design.getComponentFactory(), this); - assert tag.equals(componentMapper.componentToTag(component, this)); + assert tagEquals(tag, componentMapper.componentToTag(component, this)); return component; } + private boolean tagEquals(String tag1, String tag2) { + return tag1.equals(tag2) + || (hasVaadinPrefix(tag1) && hasVaadinPrefix(tag2)); + } + + private boolean hasVaadinPrefix(String tag) { + return tag.startsWith(LEGACY_PREFIX + "-") + || tag.startsWith(VAADIN_PREFIX + "-"); + } + /** * Instantiates given class via ComponentFactory. * diff --git a/server/tests/src/com/vaadin/tests/design/ParseNewPrefixTest.java b/server/tests/src/com/vaadin/tests/design/ParseNewPrefixTest.java new file mode 100644 index 0000000000..71811dd29a --- /dev/null +++ b/server/tests/src/com/vaadin/tests/design/ParseNewPrefixTest.java @@ -0,0 +1,46 @@ +/* + * 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.design; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; + +import org.junit.Test; + +import com.vaadin.ui.declarative.Design; +import com.vaadin.ui.declarative.DesignContext; + +/** + * Test reading a design with all components using the legacy prefix. + */ +public class ParseNewPrefixTest { + + @Test + public void allComponentsAreParsed() throws FileNotFoundException { + DesignContext ctx = Design + .read(new FileInputStream( + "server/tests/src/com/vaadin/tests/design/all-components-new.html"), + null); + + assertThat(ctx, is(not(nullValue()))); + assertThat(ctx.getRootComponent(), is(not(nullValue()))); + } +} diff --git a/server/tests/src/com/vaadin/tests/design/WriteNewDesignTest.java b/server/tests/src/com/vaadin/tests/design/WriteNewDesignTest.java new file mode 100644 index 0000000000..370f4c31c0 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/design/WriteNewDesignTest.java @@ -0,0 +1,101 @@ +/* + * 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.design; + +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.nodes.Node; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.server.Constants; +import com.vaadin.server.DefaultDeploymentConfiguration; +import com.vaadin.server.DeploymentConfiguration; +import com.vaadin.server.VaadinService; +import com.vaadin.server.VaadinServletService; +import com.vaadin.ui.declarative.Design; +import com.vaadin.ui.declarative.DesignContext; +import com.vaadin.util.CurrentInstance; + +/** + * Parse and write a new format design (using the "vaadin-" prefix). + */ +public class WriteNewDesignTest { + + // The context is used for accessing the created component hierarchy. + private DesignContext ctx; + + @Before + public void setUp() throws Exception { + Properties properties = new Properties(); + properties.put(Constants.SERVLET_PARAMETER_LEGACY_DESIGN_PREFIX, + "false"); + final DeploymentConfiguration configuration = new DefaultDeploymentConfiguration( + WriteNewDesignTest.class, properties); + + VaadinService service = new VaadinServletService(null, configuration); + + CurrentInstance.set(VaadinService.class, service); + + ctx = Design.read(new FileInputStream( + "server/tests/src/com/vaadin/tests/design/testFile-new.html"), + null); + } + + @After + public void tearDown() { + CurrentInstance.set(VaadinService.class, null); + } + + private ByteArrayOutputStream serializeDesign(DesignContext context) + throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Design.write(context, out); + + return out; + } + + @Test + public void designIsSerializedWithCorrectPrefixesAndPackageNames() + throws IOException { + ByteArrayOutputStream out = serializeDesign(ctx); + + Document doc = Jsoup.parse(out.toString("UTF-8")); + for (Node child : doc.body().childNodes()) { + checkNode(child); + } + } + + private void checkNode(Node node) { + if (node instanceof Element) { + assertTrue("Wrong design element prefix", node.nodeName() + .startsWith("vaadin-")); + for (Node child : node.childNodes()) { + checkNode(child); + } + } + } + +} diff --git a/server/tests/src/com/vaadin/tests/design/all-components-new.html b/server/tests/src/com/vaadin/tests/design/all-components-new.html new file mode 100644 index 0000000000..6507188cd7 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/design/all-components-new.html @@ -0,0 +1,122 @@ +<!DOCTYPE html> +<html> + <head> + <meta name="package-mapping" content="my:com.addon.mypackage"/> + </head> + <body> + <vaadin-vertical-layout> + <!-- abstract component --> + <vaadin-button primary-style-name="button" id="foo" style-name="red" caption="Some caption" icon="vaadin://themes/runo/icons/16/ok.png" description="My tooltip" error="Something went wrong" locale="en_US"></vaadin-button> + + <!-- absolute layout --> + <vaadin-absolute-layout> + <vaadin-button :top="100px" :left="0px" :z-index=21>OK</vaadin-button> + <vaadin-button :bottom="0px" :right="0px">Cancel</vaadin-button> + </vaadin-absolute-layout> + + <!-- vertical layout --> + <vaadin-vertical-layout spacing margin> + <vaadin-button :top>OK</vaadin-button> + <vaadin-table size-full :expand=1 /> + </vaadin-vertical-layout> + + <!-- horizontal layout --> + <vaadin-horizontal-layout spacing margin> + <vaadin-button :top>OK</vaadin-button> + <vaadin-table size-full :expand=1 /> + </vaadin-horizontal-layout> + + <!-- form layout --> + <vaadin-form-layout spacing margin> + <vaadin-button :top>OK</vaadin-button> + <vaadin-table size-full :expand=1 /> + </vaadin-form-layout> + + <!-- css layout --> + <vaadin-css-layout> + <vaadin-button>OK</vaadin-button> + <vaadin-table size-full /> + </vaadin-css-layout> + + <!-- panel --> + <vaadin-panel caption="Hello world" tabindex=2 scroll-left="10" scroll-top="10"> + <vaadin-table size-full /> + </vaadin-panel> + + <!-- abstract field --> + <vaadin-text-field buffered validation-visible=false invalid-committed invalid-allowed=false required required-error="This is a required field" conversion-error="Input {0} cannot be parsed" tabindex=3 readonly /> + <!-- abstract text field, text field --> + <vaadin-text-field null-representation="" null-setting-allowed maxlength=10 columns=5 input-prompt="Please enter a value" text-change-event-mode="eager" text-change-timeout=2 value="foo" /> + <!-- password field --> + <vaadin-password-field null-representation="" null-setting-allowed maxlength=10 columns=5 input-prompt="Please enter a value" text-change-event-mode="eager" text-change-timeout=2 value="foo" /> + <!-- text area --> + <vaadin-text-area rows=5 wordwrap=false >test value</vaadin-text-area> + <!-- button --> + <vaadin-button click-shortcut="ctrl-shift-o" disable-on-click tabindex=1 icon="http://vaadin.com/image.png" icon-alt="ok" plain-text>OK</vaadin-button> + <!-- native button --> + <vaadin-button click-shortcut="ctrl-shift-o" disable-on-click tabindex=1 icon="http://vaadin.com/image.png" icon-alt="ok" plain-text>OK</vaadin-button> + + <!-- tabsheet --> + <vaadin-tab-sheet tabindex=5> + <tab visible=false closable caption="My first tab"> + <vaadin-vertical-layout> + <vaadin-text-field/> + </vaadin-vertical-layout> + </tab> + <tab enabled=false caption="Disabled second tab"> + <vaadin-button>In disabled tab - can’t be shown by default</vaadin-button> + </tab> + <tab icon="theme://../runo/icons/16/ok.png" icon-alt="Ok png from Runo - very helpful" description="Click to show a text field" style-name="red" id="uniqueDomId"> + <vaadin-text-field input-prompt="Icon only in tab" /> + </tab> + </vaadin-tab-sheet> + + <!-- accordion --> + <vaadin-accordion tabindex=5> + <tab visible=false closable caption="My first tab"> + <vaadin-vertical-layout> + <vaadin-text-field/> + </vaadin-vertical-layout> + </tab> + <tab enabled=false caption="Disabled second tab"> + <vaadin-button>In disabled tab - can’t be shown by default</vaadin-button> + </tab> + <tab icon="theme://../runo/icons/16/ok.png" icon-alt="Ok png from Runo - very helpful" description="Click to show a text field" style-name="red" id="uniqueDomId"> + <vaadin-text-field input-prompt="Icon only in tab" /> + </tab> + </vaadin-accordion> + + <!-- abstract split panel --> + <vaadin-horizontal-split-panel split-position="20px" min-split-position="0px" max-split-position="50px" locked> + <vaadin-button>First slot</vaadin-button> + </vaadin-horizontal-split-panel> + <vaadin-vertical-split-panel split-position="25%" reversed> + <vaadin-button :second>Second slot</vaadin-button> + </vaadin-vertical-split-panel> + <vaadin-horizontal-split-panel split-position="25%" reversed> + <vaadin-button>First slot</vaadin-button> + <vaadin-button>Second slot</vaadin-button> + </vaadin-horizontal-split-panel> + + <!-- label --> + <vaadin-label>Hello world!</vaadin-label> + <vaadin-label>This is <b><u>Rich</u></b> content!</vaadin-label> + <vaadin-label plain-text>This is only <b>text</b> and will contain visible tags</vaadin-label> + + <!-- checkbox --> + <vaadin-check-box checked/> + + <!-- abstract select --> + <vaadin-list-select new-items-allowed multi-select + item-caption-mode="index" + null-selection-allowed=false> + </vaadin-list-select> + + <vaadin-combo-box> + <option icon="http://something/my-icon.png">First value</option> + <option>Second value</option> + </vaadin-combo-box> + + </vaadin-vertical-layout> + </body> +</html> diff --git a/server/tests/src/com/vaadin/tests/design/testFile-new.html b/server/tests/src/com/vaadin/tests/design/testFile-new.html new file mode 100644 index 0000000000..ab23d1d1b2 --- /dev/null +++ b/server/tests/src/com/vaadin/tests/design/testFile-new.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> + <head> + <meta name="package-mapping" content="my:com.addon.mypackage"/> + </head> + <body> + <vaadin-vertical-layout width="500px"> + <vaadin-horizontal-layout> + <vaadin-label plain-text caption="FooBar"></vaadin-label> + <vaadin-native-button _id=firstButton>Native click me</vaadin-native-button> + <vaadin-native-button id = secondButton _id="localID">Another button</vaadin-native-button> + <vaadin-native-button>Yet another button</vaadin-native-button> + <vaadin-button plain-text width = "150px">Click me</vaadin-button> + </vaadin-horizontal-layout> + <vaadin-text-field caption = "Text input"/> + <vaadin-text-area caption = "Text area" height="200px" width="300px"/> + </vaadin-vertical-layout> + </body> +</html>
\ No newline at end of file |