You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lo...@apache.org on 2020/06/05 08:38:21 UTC
[myfaces-tobago] branch master updated: Reimplement tobago-config
sort with topological sorting
This is an automated email from the ASF dual-hosted git repository.
lofwyr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git
The following commit(s) were added to refs/heads/master by this push:
new 3d6c8d5 Reimplement tobago-config sort with topological sorting
3d6c8d5 is described below
commit 3d6c8d563eb987639c4638bfc03bb555361bcd5b
Author: Udo Schnurpfeil <ud...@irian.eu>
AuthorDate: Fri Jun 5 10:37:45 2020 +0200
Reimplement tobago-config sort with topological sorting
resolves: TOBAGO-2040
---
.../internal/config/TobagoConfigBuilder.java | 4 +-
.../tobago/internal/config/TobagoConfigMerger.java | 148 +++++++++
.../tobago/internal/config/TobagoConfigSorter.java | 358 ++++++++-------------
.../config/TobagoConfigMergingUnitTest.java | 14 +-
.../config/TobagoConfigSorterUnitTest.java | 209 +++++++++---
5 files changed, 456 insertions(+), 277 deletions(-)
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigBuilder.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigBuilder.java
index 7fffb4f..8b0eb48 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigBuilder.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigBuilder.java
@@ -84,8 +84,8 @@ public class TobagoConfigBuilder {
configFromClasspath();
configFromWebInf();
final TobagoConfigSorter sorter = new TobagoConfigSorter(configFragmentList);
- sorter.sort();
- return sorter.merge();
+ final TobagoConfigMerger merger = new TobagoConfigMerger(sorter.topologicalSort());
+ return merger.merge();
}
private void configFromWebInf()
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMerger.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMerger.java
new file mode 100644
index 0000000..e6c54bf
--- /dev/null
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMerger.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.myfaces.tobago.internal.config;
+
+import org.apache.myfaces.tobago.context.ThemeImpl;
+import org.apache.myfaces.tobago.sanitizer.IgnoringSanitizer;
+import org.apache.myfaces.tobago.sanitizer.JsoupSanitizer;
+import org.apache.myfaces.tobago.sanitizer.Sanitizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.invoke.MethodHandles;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+public class TobagoConfigMerger {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ private final List<TobagoConfigFragment> list;
+
+ public TobagoConfigMerger(final List<TobagoConfigFragment> list) {
+ this.list = list;
+ }
+
+ public TobagoConfigImpl merge() {
+
+ final TobagoConfigImpl result = new TobagoConfigImpl();
+
+ // default sanitizer
+ String sanitizerClass = JsoupSanitizer.class.getName();
+ Properties sanitizerProperties = new Properties();
+ sanitizerProperties.setProperty("whitelist", "relaxed");
+
+ for (TobagoConfigFragment fragment : list) {
+
+ // default theme
+ final String defaultTheme = fragment.getDefaultThemeName();
+ if (defaultTheme != null) {
+ result.setDefaultThemeName(defaultTheme);
+ }
+
+ // supported themes
+ for (final String supported : fragment.getSupportedThemeNames()) {
+ result.addSupportedThemeName(supported);
+ }
+
+ // session secret
+ if (fragment.getCreateSessionSecret() != null) {
+ result.setCreateSessionSecret(fragment.getCreateSessionSecret());
+ }
+ if (fragment.getCheckSessionSecret() != null) {
+ result.setCheckSessionSecret(fragment.getCheckSessionSecret());
+ }
+
+ if (fragment.getPreventFrameAttacks() != null) {
+ result.setPreventFrameAttacks(fragment.getPreventFrameAttacks());
+ }
+
+ if (fragment.getContentSecurityPolicy() != null) {
+ result.getContentSecurityPolicy().merge(fragment.getContentSecurityPolicy());
+ }
+
+ if (fragment.getSecurityAnnotation() != null) {
+ result.setSecurityAnnotation(fragment.getSecurityAnnotation());
+ }
+
+ if (fragment.getSetNosniffHeader() != null) {
+ result.setSetNosniffHeader(fragment.getSetNosniffHeader());
+ }
+
+ if (fragment.getSanitizerClass() != null) {
+ sanitizerClass = fragment.getSanitizerClass();
+ sanitizerProperties = fragment.getSanitizerProperties();
+ }
+
+ if (fragment.getDecodeLineFeed() != null) {
+ result.setDecodeLineFeed(fragment.getDecodeLineFeed());
+ }
+
+ // theme definition
+ for (final ThemeImpl theme : fragment.getThemeDefinitions()) {
+ result.addAvailableTheme(theme);
+ }
+
+ // url
+ // todo???
+
+ final Map<String, String> mimeTypes = result.getMimeTypes();
+ for (final Map.Entry<String, String> entry : fragment.getMimeTypes().entrySet()) {
+ mimeTypes.put(entry.getKey(), entry.getValue());
+ }
+
+ }
+
+ resolveThemes(result, result.getAvailableThemes());
+
+ if (sanitizerClass != null) {
+ try {
+ final Class<? extends Sanitizer> aClass = Class.forName(sanitizerClass).asSubclass(Sanitizer.class);
+ final Sanitizer sanitizer = aClass.newInstance();
+ sanitizer.setProperties(sanitizerProperties);
+ result.setSanitizer(sanitizer);
+ } catch (final Exception e) {
+ LOG.error("Can't create sanitizer: '" + sanitizerClass + "'", e);
+ result.setSanitizer(new IgnoringSanitizer());
+ }
+ }
+
+ return result;
+ }
+
+ private void resolveThemes(final TobagoConfigImpl tobagoConfig, final Map<String, ThemeImpl> map) {
+ for (final ThemeImpl theme : map.values()) {
+ final String fallbackName = theme.getFallbackName();
+ final ThemeImpl fallback = map.get(fallbackName);
+ theme.setFallback(fallback);
+ }
+ for (final ThemeImpl theme : map.values()) {
+ theme.resolveFallbacks();
+ }
+ for (final ThemeImpl theme : map.values()) {
+ theme.resolveResources();
+ }
+ for (final ThemeImpl theme : map.values()) {
+ theme.init();
+ }
+ }
+
+}
diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigSorter.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigSorter.java
index b45e985..b84e3b4 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigSorter.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/config/TobagoConfigSorter.java
@@ -19,310 +19,204 @@
package org.apache.myfaces.tobago.internal.config;
-import org.apache.myfaces.tobago.context.ThemeImpl;
-import org.apache.myfaces.tobago.exception.TobagoConfigurationException;
-import org.apache.myfaces.tobago.sanitizer.IgnoringSanitizer;
-import org.apache.myfaces.tobago.sanitizer.JsoupSanitizer;
-import org.apache.myfaces.tobago.sanitizer.Sanitizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
-import java.util.Comparator;
import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-public class TobagoConfigSorter implements Comparator<TobagoConfigFragment> {
+public class TobagoConfigSorter {
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private List<TobagoConfigFragment> list;
- private List<Pair> pairs;
+ private final List<Vertex> vertices = new ArrayList<>();
- public TobagoConfigSorter(final List<TobagoConfigFragment> list) {
- this.list = list;
- }
-
- public void sort() {
-
- createRelevantPairs();
-
- makeTransitive();
-
- ensureIrreflexive();
-
- ensureAntiSymmetric();
-
- sort0();
-
- if (LOG.isInfoEnabled()) {
- LOG.info("Order of the Tobago config files:");
- for (final TobagoConfigFragment fragment : list) {
- String name = fragment.getName();
- if (name == null) {
- name = "<unnamed>";
- } else {
- name = "'" + name + "'";
- }
- LOG.info("name=" + name + " url='" + fragment.getUrl() + "'");
- }
+ public TobagoConfigSorter(final List<TobagoConfigFragment> fragmentList) {
+ for (TobagoConfigFragment tobagoConfigFragment : fragmentList) {
+ vertices.add(new Vertex(tobagoConfigFragment));
}
}
- public TobagoConfigImpl merge() {
-
- final TobagoConfigImpl result = new TobagoConfigImpl();
-
- // default sanitizer
- String sanitizerClass = JsoupSanitizer.class.getName();
- Properties sanitizerProperties = new Properties();
- sanitizerProperties.setProperty("whitelist", "relaxed");
-
- for (final TobagoConfigFragment fragment : list) {
- // default theme
- final String defaultTheme = fragment.getDefaultThemeName();
- if (defaultTheme != null) {
- result.setDefaultThemeName(defaultTheme);
- }
-
- // supported themes
- for (final String supported : fragment.getSupportedThemeNames()) {
- result.addSupportedThemeName(supported);
- }
-
- // session secret
- if (fragment.getCreateSessionSecret() != null) {
- result.setCreateSessionSecret(fragment.getCreateSessionSecret());
- }
- if (fragment.getCheckSessionSecret() != null) {
- result.setCheckSessionSecret(fragment.getCheckSessionSecret());
- }
-
- if (fragment.getPreventFrameAttacks() != null) {
- result.setPreventFrameAttacks(fragment.getPreventFrameAttacks());
- }
-
- if (fragment.getContentSecurityPolicy() != null) {
- result.getContentSecurityPolicy().merge(fragment.getContentSecurityPolicy());
- }
+ /**
+ * Topological sorting with setup and cycle check.
+ *
+ * @throws IllegalStateException When detecting a cycle.
+ */
+ public List<TobagoConfigFragment> topologicalSort() {
- if (fragment.getSecurityAnnotation() != null) {
- result.setSecurityAnnotation(fragment.getSecurityAnnotation());
- }
+ createEdges();
+ checkCycles();
- if (fragment.getSetNosniffHeader() != null) {
- result.setSetNosniffHeader(fragment.getSetNosniffHeader());
- }
-
- if (fragment.getSanitizerClass() != null) {
- sanitizerClass = fragment.getSanitizerClass();
- sanitizerProperties = fragment.getSanitizerProperties();
- }
-
- if (fragment.getDecodeLineFeed() != null) {
- result.setDecodeLineFeed(fragment.getDecodeLineFeed());
- }
-
- // theme definition
- for (final ThemeImpl theme : fragment.getThemeDefinitions()) {
- result.addAvailableTheme(theme);
- }
-
- // url
- // todo???
-
- final Map<String, String> mimeTypes = result.getMimeTypes();
- for (final Map.Entry<String, String> entry : fragment.getMimeTypes().entrySet()) {
- mimeTypes.put(entry.getKey(), entry.getValue());
- }
+ List<TobagoConfigFragment> result = new ArrayList<>();
+ for (Vertex vertex : vertices) {
+ topologicalSort0(vertex, result);
}
- resolveThemes(result, result.getAvailableThemes());
-
- if (sanitizerClass != null) {
- try {
- final Class<? extends Sanitizer> aClass = Class.forName(sanitizerClass).asSubclass(Sanitizer.class);
- final Sanitizer sanitizer = aClass.newInstance();
- sanitizer.setProperties(sanitizerProperties);
- result.setSanitizer(sanitizer);
- } catch (final Exception e) {
- LOG.error("Can't create sanitizer: '" + sanitizerClass + "'", e);
- result.setSanitizer(new IgnoringSanitizer());
- }
- }
+ logResult(result);
return result;
}
- protected void makeTransitive() {
- // make the half order transitive: a < b && b < c => a < c
- boolean growing = true;
- while (growing) {
- growing = false;
- for (int i = 0; i < pairs.size(); i++) {
- for (int j = 0; j < pairs.size(); j++) {
- if (pairs.get(i).getHigher() == pairs.get(j).getLower()
- && !isInRelation(pairs.get(i).getLower(), pairs.get(j).getHigher())) {
- pairs.add(new Pair(pairs.get(i).getLower(), pairs.get(j).getHigher()));
- growing = true;
- }
- }
- }
+ /**
+ * Internal recursive method for the topological sort.
+ */
+ private void topologicalSort0(Vertex vertex, List<TobagoConfigFragment> result) {
+ if (vertex.isVisited()) {
+ return;
}
- }
- protected void ensureIrreflexive() {
- for (final Pair a : pairs) {
- if (a.getLower() == a.getHigher()) {
- final StringBuilder buffer = new StringBuilder();
- buffer.append("Ordering problem. There are conflicting order rules. Not irreflexive. '");
- buffer.append(a.getLower());
- buffer.append("' < '");
- buffer.append(a.getHigher());
- buffer.append("'!\nThe reason may be a cycle.\n");
- buffer.append("Complete list of rules: \n");
- for (final Pair pair : pairs) {
- buffer.append("'");
- buffer.append(pair.getLower());
- buffer.append("' < '");
- buffer.append(pair.getHigher());
- buffer.append("'\n");
+ vertex.setVisited(true);
- }
- throw new TobagoConfigurationException(buffer.toString());
- }
- }
- }
+ // recursion for all vertices adjacent to this vertex
+ for (Vertex adjacent : vertex.getAdjacencyList()) {
+ topologicalSort0(adjacent, result);
+ }
- protected void ensureAntiSymmetric() {
- for (final Pair a : pairs) {
- for (final Pair b : pairs) {
- if (a.getLower() == b.getHigher() && a.getHigher() == b.getLower()) {
- final StringBuilder buffer = new StringBuilder();
- buffer.append("Ordering problem. There are conflicting order rules. Not antisymmetric. '");
- buffer.append(a.getLower());
- buffer.append("' < '");
- buffer.append(a.getHigher());
- buffer.append("'" + "'");
- buffer.append(a.getLower());
- buffer.append("' > '");
- buffer.append(a.getHigher());
- buffer.append("'!\nThe reason may be a cycle.\n");
- buffer.append("Complete list of rules: \n");
- for (final Pair pair : pairs) {
- buffer.append("'");
- buffer.append(pair.getLower());
- buffer.append("' < '");
- buffer.append(pair.getHigher());
- buffer.append("'\n");
+ result.add(vertex.getFragment());
+ }
+ private void logResult(List<TobagoConfigFragment> result) {
+ if (LOG.isInfoEnabled()) {
+ StringBuilder builder = new StringBuilder("Order of the Tobago config files: ");
+ for (TobagoConfigFragment fragment : result) {
+ final String name = fragment.getName();
+ if (LOG.isDebugEnabled()) {
+ builder.append("name=");
+ if (name == null) {
+ builder.append("<unnamed>");
+ } else {
+ builder.append("'");
+ builder.append(name);
+ builder.append("'");
}
- throw new TobagoConfigurationException(buffer.toString());
+ builder.append(" url='");
+ builder.append(fragment.getUrl());
+ builder.append("'");
+ } else {
+ builder.append(name);
+ builder.append(", ");
}
}
+ LOG.info(builder.toString());
}
}
- @Override
- public int compare(final TobagoConfigFragment a, final TobagoConfigFragment b) {
- if (isInRelation(a, b)) {
- return -1;
- }
- if (isInRelation(b, a)) {
- return 1;
- }
- return 0;
- }
- protected void createRelevantPairs() {
-
- pairs = new ArrayList<>();
+ private void createEdges() {
// collecting all relations, which are relevant for us. We don't need "before" and "after" of unknown names.
- for (final TobagoConfigFragment tobagoConfig : list) {
- for (final String befores : tobagoConfig.getBefore()) {
+ for (final Vertex vertex : vertices) {
+ final TobagoConfigFragment current = vertex.getFragment();
+
+ for (final String befores : current.getBefore()) {
final TobagoConfigFragment before = findByName(befores);
if (before != null) {
- pairs.add(new Pair(tobagoConfig, before));
+ findVertex(before).addAdjacent(findVertex(current));
}
}
- for (final String afters : tobagoConfig.getAfter()) {
+ for (final String afters : current.getAfter()) {
final TobagoConfigFragment after = findByName(afters);
if (after != null) {
- pairs.add(new Pair(after, tobagoConfig));
+ findVertex(current).addAdjacent(findVertex(after));
}
}
}
}
- protected void sort0() {
- list.sort(this);
+ /**
+ * Cycle detection: if the base in reachable form its own, than there is a cycle.
+ *
+ * @throws IllegalStateException When detecting a cycle.
+ */
+ private void checkCycles() {
+ LOG.debug("Cycle detection:");
+ for (Vertex vertex : vertices) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Checking reachable vertices from base {}", vertex.getFragment());
+ }
+ checkCycles0(vertex, vertex);
+ }
}
- private boolean isInRelation(final TobagoConfigFragment lower, final TobagoConfigFragment higher) {
- for (final Pair p : pairs) {
- if (p.getLower() == lower && p.getHigher() == higher) {
- return true;
+ private void checkCycles0(final Vertex vertex, final Vertex base) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("vertex: {}", vertex.toString());
+ LOG.debug("base: {}", base.getFragment().toString());
+ }
+ for (Vertex adjacent : vertex.getAdjacencyList()) {
+ if (base == adjacent) {
+ throw new IllegalStateException("Cycle detected name='" + vertex + "' base=" + base + "! ");
}
+ checkCycles0(adjacent, base);
}
- return false;
}
- private TobagoConfigFragment findByName(final String name) {
- for (final TobagoConfigFragment tobagoConfig : list) {
- if (name.equals(tobagoConfig.getName())) {
- return tobagoConfig;
+ private Vertex findVertex(final TobagoConfigFragment fragment) {
+ for (Vertex vertex : vertices) {
+ if (vertex.getFragment() == fragment) {
+ return vertex;
}
}
- return null;
+ throw new RuntimeException("Problem with sorting! This might be a bug.");
}
- private void resolveThemes(final TobagoConfigImpl tobagoConfig, final Map<String, ThemeImpl> map) {
- for (final ThemeImpl theme : map.values()) {
- final String fallbackName = theme.getFallbackName();
- final ThemeImpl fallback = map.get(fallbackName);
- theme.setFallback(fallback);
- }
- for (final ThemeImpl theme : map.values()) {
- theme.resolveFallbacks();
- }
- for (final ThemeImpl theme : map.values()) {
- theme.resolveResources();
- }
- for (final ThemeImpl theme : map.values()) {
- theme.init();
+ private TobagoConfigFragment findByName(final String name) {
+ for (final Vertex vertex : vertices) {
+ TobagoConfigFragment fragment = vertex.getFragment();
+ if (name.equals(fragment.getName())) {
+ return fragment;
+ }
}
+ return null;
}
- protected List<Pair> getPairs() {
- return pairs;
- }
+ private static class Vertex {
- private static class Pair {
+ private final TobagoConfigFragment fragment;
+ private final List<Vertex> adjacencyList;
+ private boolean visited;
- private final TobagoConfigFragment lower;
- private final TobagoConfigFragment higher;
+ private Vertex(final TobagoConfigFragment fragment) {
+ this.fragment = fragment;
+ this.adjacencyList = new ArrayList<>();
+ }
- private Pair(final TobagoConfigFragment lower, final TobagoConfigFragment higher) {
- this.lower = lower;
- this.higher = higher;
+ public boolean isVisited() {
+ return visited;
}
- public TobagoConfigFragment getLower() {
- return lower;
+ public void setVisited(boolean visited) {
+ this.visited = visited;
}
- public TobagoConfigFragment getHigher() {
- return higher;
+ public TobagoConfigFragment getFragment() {
+ return fragment;
+ }
+
+ public void addAdjacent(Vertex higher) {
+ adjacencyList.add(higher);
+ }
+
+ public List<Vertex> getAdjacencyList() {
+ return adjacencyList;
}
@Override
public String toString() {
- return lower + "<" + higher;
+ StringBuilder builder = new StringBuilder();
+ builder.append(fragment);
+ builder.append(" -> [");
+ for (Vertex vertex : adjacencyList) {
+ builder.append(vertex.getFragment());
+ builder.append(", ");
+ }
+ if (builder.charAt(builder.length() - 1) == ' ') {
+ builder.delete(builder.length() - 2, builder.length());
+ }
+ builder.append("]");
+ return builder.toString();
}
}
-
}
diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMergingUnitTest.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMergingUnitTest.java
index ff76081..c051e34 100644
--- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMergingUnitTest.java
+++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigMergingUnitTest.java
@@ -70,7 +70,7 @@ public class TobagoConfigMergingUnitTest {
final TobagoConfigImpl config = loadAndMerge(
"tobago-config-merge-0.xml");
- Assertions.assertTrue(config.getContentSecurityPolicy().getMode() == ContentSecurityPolicy.Mode.ON);
+ Assertions.assertSame(config.getContentSecurityPolicy().getMode(), ContentSecurityPolicy.Mode.ON);
final Map<String, String> directiveMap = config.getContentSecurityPolicy().getDirectiveMap();
Assertions.assertEquals(1, directiveMap.size());
Assertions.assertEquals("'self'", directiveMap.get("default-src"));
@@ -84,7 +84,7 @@ public class TobagoConfigMergingUnitTest {
"tobago-config-merge-0.xml",
"tobago-config-merge-1.xml");
- Assertions.assertTrue(config.getContentSecurityPolicy().getMode() == ContentSecurityPolicy.Mode.REPORT_ONLY);
+ Assertions.assertSame(config.getContentSecurityPolicy().getMode(), ContentSecurityPolicy.Mode.REPORT_ONLY);
final Map<String, String> directiveMap = config.getContentSecurityPolicy().getDirectiveMap();
Assertions.assertEquals(2, directiveMap.size());
Assertions.assertEquals("'self'", directiveMap.get("default-src"));
@@ -100,7 +100,7 @@ public class TobagoConfigMergingUnitTest {
"tobago-config-merge-1.xml",
"tobago-config-merge-2.xml");
- Assertions.assertTrue(config.getContentSecurityPolicy().getMode() == ContentSecurityPolicy.Mode.OFF);
+ Assertions.assertSame(config.getContentSecurityPolicy().getMode(), ContentSecurityPolicy.Mode.OFF);
Assertions.assertEquals(2, config.getContentSecurityPolicy().getDirectiveMap().size());
}
@@ -112,7 +112,7 @@ public class TobagoConfigMergingUnitTest {
"tobago-config-merge-0.xml",
"tobago-config-merge-3.xml");
- Assertions.assertTrue(config.getContentSecurityPolicy().getMode() == ContentSecurityPolicy.Mode.ON);
+ Assertions.assertSame(config.getContentSecurityPolicy().getMode(), ContentSecurityPolicy.Mode.ON);
final Map<String, String> directiveMap = config.getContentSecurityPolicy().getDirectiveMap();
Assertions.assertEquals(1, directiveMap.size());
Assertions.assertEquals("'self' https:", directiveMap.get("default-src"));
@@ -128,7 +128,7 @@ public class TobagoConfigMergingUnitTest {
"tobago-config-merge-2.xml");
final Map<String, String> mimeTypes = config.getMimeTypes();
- Assertions.assertTrue(mimeTypes.size() == 3);
+ Assertions.assertEquals(3, mimeTypes.size());
Assertions.assertEquals("test/one", mimeTypes.get("test-1"));
Assertions.assertEquals("test/zwei", mimeTypes.get("test-2"));
Assertions.assertEquals("test/three", mimeTypes.get("test-3"));
@@ -178,7 +178,7 @@ public class TobagoConfigMergingUnitTest {
}
final TobagoConfigSorter sorter = new TobagoConfigSorter(list);
- sorter.sort();
- return sorter.merge();
+ final TobagoConfigMerger merger = new TobagoConfigMerger(sorter.topologicalSort());
+ return merger.merge();
}
}
diff --git a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigSorterUnitTest.java b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigSorterUnitTest.java
index bb52c43..d71964a 100644
--- a/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigSorterUnitTest.java
+++ b/tobago-core/src/test/java/org/apache/myfaces/tobago/internal/config/TobagoConfigSorterUnitTest.java
@@ -21,12 +21,17 @@ package org.apache.myfaces.tobago.internal.config;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.List;
public class TobagoConfigSorterUnitTest {
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
@Test
public void testCompare() {
@@ -95,35 +100,85 @@ public class TobagoConfigSorterUnitTest {
list.add(n);
final TobagoConfigSorter sorter = new TobagoConfigSorter(list);
- sorter.createRelevantPairs();
+ final List<TobagoConfigFragment> result = sorter.topologicalSort();
+
+ Assertions.assertEquals(a, result.get(0));
+ Assertions.assertEquals(b, result.get(1));
+ Assertions.assertEquals(c, result.get(2));
+ Assertions.assertEquals(u1, result.get(3));
+ Assertions.assertEquals(u2, result.get(4));
+ Assertions.assertEquals(d, result.get(5));
+ Assertions.assertEquals(e, result.get(6));
+ Assertions.assertEquals(f, result.get(7));
+ Assertions.assertEquals(u3, result.get(8));
+ Assertions.assertEquals(m, result.get(9));
+ Assertions.assertEquals(n, result.get(10));
+ }
+
+ @Test
+ public void test0() {
+
+ // config + names
+
+ final List<TobagoConfigFragment> list = new ArrayList<>();
+
+ final TobagoConfigSorter sorter = new TobagoConfigSorter(list);
+
+ final List<TobagoConfigFragment> result = sorter.topologicalSort();
+
+ Assertions.assertTrue(result.isEmpty());
+ }
+
+ @Test
+ public void testCycle1Before() {
+
+ // config + names
+
+ final TobagoConfigFragment a = new TobagoConfigFragment();
+ a.setName("a");
+
+ a.getBefore().add("a");
+
+ final List<TobagoConfigFragment> list = new ArrayList<>();
+ list.add(a);
+
+ final TobagoConfigSorter sorter = new TobagoConfigSorter(list);
+
+ try {
+ sorter.topologicalSort();
+
+ Assertions.fail("Cycle was not detected!");
+ } catch (final RuntimeException e) {
+ LOG.info("Success: Cycle found: {}", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testCycle1After() {
- Assertions.assertEquals(9, sorter.getPairs().size()); // all but these with "z" and "y"
+ // config + names
- sorter.makeTransitive();
+ final TobagoConfigFragment a = new TobagoConfigFragment();
+ a.setName("a");
- Assertions.assertEquals(28, sorter.getPairs().size());
+ a.getAfter().add("a");
- sorter.ensureIrreflexive();
+ final List<TobagoConfigFragment> list = new ArrayList<>();
+ list.add(a);
- sorter.ensureAntiSymmetric();
+ final TobagoConfigSorter sorter = new TobagoConfigSorter(list);
- sorter.sort0();
+ try {
+ sorter.topologicalSort();
- Assertions.assertEquals(a, list.get(0));
- Assertions.assertEquals(b, list.get(1));
- Assertions.assertEquals(c, list.get(2));
- Assertions.assertEquals(u1, list.get(3));
- Assertions.assertEquals(u2, list.get(4));
- Assertions.assertEquals(d, list.get(5));
- Assertions.assertEquals(e, list.get(6));
- Assertions.assertEquals(f, list.get(7));
- Assertions.assertEquals(u3, list.get(8));
- Assertions.assertEquals(m, list.get(9));
- Assertions.assertEquals(n, list.get(10));
+ Assertions.fail("Cycle was not detected!");
+ } catch (final RuntimeException e) {
+ LOG.info("Success: Cycle found: {}", e.getMessage());
+ }
}
@Test
- public void testCycle() {
+ public void testCycle2() {
// config + names
@@ -142,24 +197,18 @@ public class TobagoConfigSorterUnitTest {
list.add(b);
final TobagoConfigSorter sorter = new TobagoConfigSorter(list);
- sorter.createRelevantPairs();
-
- Assertions.assertEquals(2, sorter.getPairs().size()); // all but these with "z" and "y"
-
- sorter.makeTransitive();
try {
- sorter.ensureIrreflexive();
- sorter.ensureAntiSymmetric();
+ sorter.topologicalSort();
- Assertions.fail("Cycle was not found");
+ Assertions.fail("Cycle was not detected!");
} catch (final RuntimeException e) {
- // must find the cycle
+ LOG.info("Success: Cycle found: {}", e.getMessage());
}
}
@Test
- public void testCycle2() {
+ public void testCycle2BeforeAfter() {
// config + names
@@ -179,19 +228,107 @@ public class TobagoConfigSorterUnitTest {
list.add(b);
final TobagoConfigSorter sorter = new TobagoConfigSorter(list);
- sorter.createRelevantPairs();
+ try {
+ sorter.topologicalSort();
- Assertions.assertEquals(2, sorter.getPairs().size()); // all but these with "z" and "y"
+ Assertions.fail("Cycle was not detected!");
+ } catch (final RuntimeException e) {
+ LOG.info("Success: Cycle found: {}", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testCycle3() {
+
+ // config + names
+
+ final TobagoConfigFragment a = new TobagoConfigFragment();
+ a.setName("a");
+
+ final TobagoConfigFragment b = new TobagoConfigFragment();
+ b.setName("b");
+
+ final TobagoConfigFragment c = new TobagoConfigFragment();
+ c.setName("c");
+
+ // before
+ a.getBefore().add("b");
+ b.getBefore().add("c");
+ a.getAfter().add("c");
- sorter.makeTransitive();
+ final List<TobagoConfigFragment> list = new ArrayList<>();
+ list.add(a);
+ list.add(b);
+ list.add(c);
+
+ final TobagoConfigSorter sorter = new TobagoConfigSorter(list);
try {
- sorter.ensureIrreflexive();
- sorter.ensureAntiSymmetric();
+ sorter.topologicalSort();
- Assertions.fail("Cycle was not found");
+ Assertions.fail("Cycle was not detected!");
} catch (final RuntimeException e) {
- // must find the cycle
+ LOG.info("Success: Cycle found: {}", e.getMessage());
}
}
+
+ @Test
+ public void testReal() {
+
+ // config + names
+
+ final TobagoConfigFragment blank = new TobagoConfigFragment();
+ blank.setName("tobago-example-blank");
+
+ final TobagoConfigFragment charlotteville = new TobagoConfigFragment();
+ charlotteville.setName("tobago-theme-charlotteville");
+
+ final TobagoConfigFragment roxborough = new TobagoConfigFragment();
+ roxborough.setName("tobago-theme-roxborough");
+
+ final TobagoConfigFragment scarborough = new TobagoConfigFragment();
+ scarborough.setName("tobago-theme-scarborough");
+
+ final TobagoConfigFragment speyside = new TobagoConfigFragment();
+ speyside.setName("tobago-theme-speyside");
+
+ final TobagoConfigFragment standard = new TobagoConfigFragment();
+ standard.setName("tobago-theme-standard");
+
+ final TobagoConfigFragment core = new TobagoConfigFragment();
+ core.setName("tobago-core");
+
+ // after
+ blank.getAfter().add(speyside.getName());
+ blank.getAfter().add(scarborough.getName());
+ blank.getAfter().add(roxborough.getName());
+ blank.getAfter().add(standard.getName());
+ blank.getAfter().add(charlotteville.getName());
+ charlotteville.getAfter().add(standard.getName());
+ roxborough.getAfter().add(standard.getName());
+ scarborough.getAfter().add(standard.getName());
+ speyside.getAfter().add(standard.getName());
+ standard.getAfter().add(core.getName());
+
+
+ final List<TobagoConfigFragment> list = new ArrayList<>();
+ list.add(blank);
+ list.add(charlotteville);
+ list.add(roxborough);
+ list.add(scarborough);
+ list.add(speyside);
+ list.add(standard);
+ list.add(core);
+
+ final TobagoConfigSorter sorter = new TobagoConfigSorter(list);
+
+ final List<TobagoConfigFragment> result = sorter.topologicalSort();
+
+ Assertions.assertEquals(core, result.get(0));
+ Assertions.assertEquals(standard, result.get(1));
+ Assertions.assertEquals(blank, result.get(6));
+ final int blankPos = result.indexOf(blank);
+ final int speysidePos = result.indexOf(speyside);
+ Assertions.assertTrue(blankPos > speysidePos);
+ }
}