View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.tobago.internal.config;
21  
22  import org.slf4j.Logger;
23  import org.slf4j.LoggerFactory;
24  
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.Comparator;
28  import java.util.List;
29  
30  public class TobagoConfigSorter implements Comparator<TobagoConfigFragment> {
31  
32    private static final Logger LOG = LoggerFactory.getLogger(TobagoConfigSorter.class);
33  
34    private List<TobagoConfigFragment> list;
35    private List<Pair> pairs;
36  
37    public TobagoConfigSorter(List<TobagoConfigFragment> list) {
38      this.list = list;
39    }
40  
41    public void sort() {
42  
43      createRelevantPairs();
44  
45      makeTransitive();
46  
47      ensureIrreflexive();
48  
49      ensureAntiSymmetric();
50  
51      sort0();
52  
53      if (LOG.isInfoEnabled()) {
54        LOG.info("Order of the Tobago config files:");
55        for (TobagoConfigFragment fragment : list) {
56          String name = fragment.getName();
57          if (name == null) {
58            name = "<unnamed>";
59          } else {
60            name = "'" + name + "'";
61          }
62          LOG.info("name=" + name + " url='" + fragment.getUrl() + "'");
63        }
64      }
65    }
66  
67    public TobagoConfigImpl merge() {
68  // todo
69      LOG.warn("Merge implementation in progress...)");
70  
71      TobagoConfigImpl result = new TobagoConfigImpl();
72  
73      for (TobagoConfigFragment fragment : list) {
74        // default theme
75        final String defaultTheme = fragment.getDefaultThemeName();
76        if (defaultTheme != null) {
77          result.setDefaultThemeName(defaultTheme);
78        }
79  
80        // supported themes
81        for (String supported : fragment.getSupportedThemeNames()) {
82          result.addSupportedThemeName(supported);
83        }
84  
85        // resource dirs
86        for (String dir : fragment.getResourceDirs()) {
87          result.addResourceDir(dir);
88        }
89  
90        // renderers config
91        // TODO: merging not implemented yet!!!
92        result.setRenderersConfig(fragment.getRenderersConfig());
93  
94        // session secret
95        if (fragment.getCreateSessionSecret() != null) {
96          result.setCreateSessionSecret(fragment.getCreateSessionSecret());
97        }
98        if (fragment.getCheckSessionSecret() != null) {
99          result.setCheckSessionSecret(fragment.getCheckSessionSecret());
100       }
101 
102       if (fragment.getPreventFrameAttacks() != null) {
103         result.setPreventFrameAttacks(fragment.getPreventFrameAttacks());
104       }
105 
106       if (fragment.getContentSecurityPolicy() != null) {
107         result.getContentSecurityPolicy().merge(fragment.getContentSecurityPolicy());
108       }
109 
110       // theme definition
111       // todo
112 /*
113       for (Theme theme : fragment.getThemeDefinitions()) {
114         result.addThemeDefinition(theme);
115       }
116 */
117 
118       // url
119       // todo???
120 
121     }
122     return result;
123   }
124 
125   protected void makeTransitive() {
126     // make the half order transitive: a < b && b < c => a < c
127     boolean growing = true;
128     while (growing) {
129       growing = false;
130       for (int i = 0; i < pairs.size(); i++) {
131         for (int j = 0; j < pairs.size(); j++) {
132           if (pairs.get(i).getHigher() == pairs.get(j).getLower()
133               && !isInRelation(pairs.get(i).getLower(), pairs.get(j).getHigher())) {
134             pairs.add(new Pair(pairs.get(i).getLower(), pairs.get(j).getHigher()));
135             growing = true;
136           }
137         }
138       }
139     }
140   }
141 
142   protected void ensureIrreflexive() {
143     for (Pair a : pairs) {
144         if (a.getLower() == a.getHigher()) {
145           StringBuffer buffer = new StringBuffer();
146           buffer.append("Ordering problem. There are conflicting order rules. Not irreflexive. " + "'");
147           buffer.append(a.getLower());
148           buffer.append("' < '");
149           buffer.append(a.getHigher());
150           buffer.append("'!\nThe reason may be a cycle.\n");
151           buffer.append("Complete list of rules: \n");
152           for (Pair pair : pairs) {
153             buffer.append("'");
154             buffer.append(pair.getLower());
155             buffer.append("' < '");
156             buffer.append(pair.getHigher());
157             buffer.append("'\n");
158 
159           }
160           throw new RuntimeException(buffer.toString());
161         }
162       }
163   }
164 
165   protected void ensureAntiSymmetric() {
166     for (Pair a : pairs) {
167       for (Pair b : pairs) {
168         if (a.getLower() == b.getHigher() && a.getHigher() == b.getLower()) {
169           StringBuffer buffer = new StringBuffer();
170           buffer.append("Ordering problem. There are conflicting order rules. Not antisymmetric. " + "'");
171           buffer.append(a.getLower());
172           buffer.append("' < '");
173           buffer.append(a.getHigher());
174           buffer.append("'" + "'");
175           buffer.append(a.getLower());
176           buffer.append("' > '");
177           buffer.append(a.getHigher());
178           buffer.append("'!\nThe reason may be a cycle.\n");
179           buffer.append("Complete list of rules: \n");
180           for (Pair pair : pairs) {
181             buffer.append("'");
182             buffer.append(pair.getLower());
183             buffer.append("' < '");
184             buffer.append(pair.getHigher());
185             buffer.append("'\n");
186 
187           }
188           throw new RuntimeException(buffer.toString());
189         }
190       }
191     }
192   }
193 
194   public int compare(TobagoConfigFragment a, TobagoConfigFragment b) {
195     if (isInRelation(a, b)) {
196       return -1;
197     }
198     if (isInRelation(b, a)) {
199       return 1;
200     }
201     return 0;
202   }
203 
204   protected void createRelevantPairs() {
205 
206     pairs = new ArrayList<Pair>();
207 
208     // collecting all relations, which are relevant for us. We don't need "before" and "after" of unknown names.
209     for (TobagoConfigFragment tobagoConfig : list) {
210       for (String befores : tobagoConfig.getBefore()) {
211         TobagoConfigFragment before = findByName(befores);
212         if (before != null) {
213           pairs.add(new Pair(tobagoConfig, before));
214         }
215       }
216       for (String afters : tobagoConfig.getAfter()) {
217         TobagoConfigFragment after = findByName(afters);
218         if (after != null) {
219           pairs.add(new Pair(after, tobagoConfig));
220         }
221       }
222     }
223   }
224 
225   protected void sort0() {
226     Collections.sort(list, this);
227   }
228 
229   private boolean isInRelation(TobagoConfigFragment lower, TobagoConfigFragment higher) {
230     for (Pair p : pairs) {
231       if (p.getLower() == lower && p.getHigher() == higher) {
232         return true;
233       }
234     }
235     return false;
236   }
237 
238   private TobagoConfigFragment findByName(String name) {
239     for (TobagoConfigFragment tobagoConfig : list) {
240       if (name.equals(tobagoConfig.getName())) {
241         return tobagoConfig;
242       }
243     }
244     return null;
245   }
246 
247   protected List<Pair> getPairs() {
248     return pairs;
249   }
250 
251   private static class Pair {
252 
253     private final TobagoConfigFragment lower;
254     private final TobagoConfigFragment higher;
255 
256     private Pair(TobagoConfigFragment lower, TobagoConfigFragment higher) {
257       this.lower = lower;
258       this.higher = higher;
259     }
260 
261     public TobagoConfigFragment getLower() {
262       return lower;
263     }
264 
265     public TobagoConfigFragment getHigher() {
266       return higher;
267     }
268 
269     @Override
270     public String toString() {
271       return lower + "<" + higher;
272     }
273   }
274 
275 }