View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.start;
20  
21  import java.io.BufferedReader;
22  import java.io.File;
23  import java.io.FileNotFoundException;
24  import java.io.FileReader;
25  import java.io.IOException;
26  import java.text.CollationKey;
27  import java.text.Collator;
28  import java.util.ArrayList;
29  import java.util.Collections;
30  import java.util.Comparator;
31  import java.util.HashSet;
32  import java.util.List;
33  import java.util.Set;
34  import java.util.regex.Matcher;
35  import java.util.regex.Pattern;
36  
37  /**
38   * Represents a Module metadata, as defined in Jetty.
39   */
40  public class Module
41  {
42      public static class NameComparator implements Comparator<Module>
43      {
44          private Collator collator = Collator.getInstance();
45  
46          @Override
47          public int compare(Module o1, Module o2)
48          {
49              // by name (not really needed, but makes for predictable test cases)
50              CollationKey k1 = collator.getCollationKey(o1.name);
51              CollationKey k2 = collator.getCollationKey(o2.name);
52              return k1.compareTo(k2);
53          }
54      }
55  
56      public static class DepthComparator implements Comparator<Module>
57      {
58          private Collator collator = Collator.getInstance();
59  
60          @Override
61          public int compare(Module o1, Module o2)
62          {
63              // order by depth first.
64              int diff = o1.depth - o2.depth;
65              if (diff != 0)
66              {
67                  return diff;
68              }
69              // then by name (not really needed, but makes for predictable test cases)
70              CollationKey k1 = collator.getCollationKey(o1.name);
71              CollationKey k2 = collator.getCollationKey(o2.name);
72              return k1.compareTo(k2);
73          }
74      }
75  
76      /** The file of the module */
77      private File file;
78      /** The name of this Module */
79      private String name;
80      /** The depth of the module in the tree */
81      private int depth = 0;
82      /** List of Modules, by name, that this Module depends on */
83      private Set<String> parentNames;
84      /** List of Modules, by name, that this Module optionally depend on */
85      private Set<String> optionalParentNames;
86      /** The Edges to parent modules */
87      private Set<Module> parentEdges;
88      /** The Edges to child modules */
89      private Set<Module> childEdges;
90      /** List of xml configurations for this Module */
91      private List<String> xmls;
92      /** List of ini template lines */
93      private List<String> initialise;
94      /** List of library options for this Module */
95      private List<String> libs;
96      /** List of files for this Module */
97      private List<String> files;
98  
99      /** Is this Module enabled via start.jar command line, start.ini, or start.d/*.ini ? */
100     private boolean enabled = false;
101     /** List of sources that enabled this module */
102     private final Set<String> sources = new HashSet<>();
103 
104     public Module(File file) throws FileNotFoundException, IOException
105     {
106         this.file = file;
107 
108         String name = file.getName();
109         // Strip .ini
110         name = Pattern.compile(".mod$",Pattern.CASE_INSENSITIVE).matcher(name).replaceFirst("");
111 
112         init();
113         process();
114     }
115 
116     public void addChildEdge(Module child)
117     {
118         if (childEdges.contains(child))
119         {
120             // already present, skip
121             return;
122         }
123         this.childEdges.add(child);
124     }
125 
126     public void addParentEdge(Module parent)
127     {
128         if (parentEdges.contains(parent))
129         {
130             // already present, skip
131             return;
132         }
133         this.parentEdges.add(parent);
134     }
135 
136     @Override
137     public boolean equals(Object obj)
138     {
139         if (this == obj)
140         {
141             return true;
142         }
143         if (obj == null)
144         {
145             return false;
146         }
147         if (getClass() != obj.getClass())
148         {
149             return false;
150         }
151         Module other = (Module)obj;
152         if (name == null)
153         {
154             if (other.name != null)
155             {
156                 return false;
157             }
158         }
159         else if (!name.equals(other.name))
160         {
161             return false;
162         }
163         return true;
164     }
165 
166     public Set<Module> getChildEdges()
167     {
168         return childEdges;
169     }
170 
171     public int getDepth()
172     {
173         return depth;
174     }
175 
176     public List<String> getLibs()
177     {
178         return libs;
179     }
180 
181     public String getName()
182     {
183         return name;
184     }
185 
186     public Set<String> getOptionalParentNames()
187     {
188         return optionalParentNames;
189     }
190 
191     public Set<Module> getParentEdges()
192     {
193         return parentEdges;
194     }
195 
196     public Set<String> getParentNames()
197     {
198         return parentNames;
199     }
200 
201     public List<String> getXmls()
202     {
203         return xmls;
204     }
205 
206     public List<String> getInitialise()
207     {
208         return initialise;
209     }
210 
211     public List<String> getFiles()
212     {
213         return files;
214     }
215 
216     @Override
217     public int hashCode()
218     {
219         final int prime = 31;
220         int result = 1;
221         result = (prime * result) + ((name == null)?0:name.hashCode());
222         return result;
223     }
224 
225     public void init()
226     {
227         String name = file.getName();
228 
229         // Strip .ini
230         this.name = Pattern.compile(".mod$",Pattern.CASE_INSENSITIVE).matcher(name).replaceFirst("");
231 
232         parentNames = new HashSet<>();
233         optionalParentNames = new HashSet<>();
234         parentEdges = new HashSet<>();
235         childEdges = new HashSet<>();
236         xmls = new ArrayList<>();
237         initialise = new ArrayList<>();
238         libs = new ArrayList<>();
239         files = new ArrayList<>();
240     }
241 
242     public boolean isEnabled()
243     {
244         return enabled;
245     }
246 
247     public void process() throws FileNotFoundException, IOException
248     {
249         Pattern section = Pattern.compile("\\s*\\[([^]]*)\\]\\s*");
250 
251         if (!FS.canReadFile(file))
252         {
253             StartLog.debug("Skipping read of missing file: %s",file.getAbsolutePath());
254             return;
255         }
256 
257         try (FileReader reader = new FileReader(file))
258         {
259             try (BufferedReader buf = new BufferedReader(reader))
260             {
261                 String line;
262                 String sectionType = "";
263                 while ((line = buf.readLine()) != null)
264                 {
265                     line = line.trim();
266                     Matcher sectionMatcher = section.matcher(line);
267 
268                     if (sectionMatcher.matches())
269                     {
270                         sectionType = sectionMatcher.group(1).trim().toUpperCase();
271                     }
272                     else
273                     {
274                         // blank lines and comments are valid for initialize section
275                         if (line.length() == 0 || line.startsWith("#"))
276                         {
277                             if ("INI-TEMPLATE".equals(sectionType))
278                             {
279                                 initialise.add(line);
280                             }
281                         }
282                         else
283                         {
284                             switch (sectionType)
285                             {
286                                 case "DEPEND":
287                                     parentNames.add(line);
288                                     break;
289                                 case "LIB":
290                                     libs.add(line);
291                                     break;
292                                 case "XML":
293                                     xmls.add(line);
294                                     break;
295                                 case "OPTIONAL":
296                                     optionalParentNames.add(line);
297                                     break;
298                                 case "FILES":
299                                     files.add(line);
300                                     break;                             
301                                 case "INI-TEMPLATE":
302                                     initialise.add(line);
303                                     break;
304                             }
305                         }
306                     }
307                 }
308             }
309         }
310     }
311 
312     public void setDepth(int depth)
313     {
314         this.depth = depth;
315     }
316 
317     public void setEnabled(boolean enabled)
318     {
319         this.enabled = enabled;
320     }
321 
322     public void addSources(List<String> sources)
323     {
324         this.sources.addAll(sources);
325     }
326 
327     public void clearSources()
328     {
329         this.sources.clear();
330     }
331 
332     public Set<String> getSources()
333     {
334         return Collections.unmodifiableSet(sources);
335     }
336 
337     @Override
338     public String toString()
339     {
340         StringBuilder str = new StringBuilder();
341         str.append("Module[").append(name);
342         if (enabled)
343         {
344             str.append(",enabled");
345         }
346         str.append(']');
347         return str.toString();
348     }
349 }