View Javadoc
1   /*
2    * This file is part of ***  M y C o R e  ***
3    * See http://www.mycore.de/ for details.
4    *
5    * MyCoRe is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * MyCoRe is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with MyCoRe.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package org.mycore.common.config;
20  
21  import java.io.File;
22  import java.io.InputStream;
23  import java.net.URL;
24  import java.text.NumberFormat;
25  import java.util.Locale;
26  import java.util.Map;
27  import java.util.jar.Manifest;
28  
29  import org.apache.logging.log4j.Logger;
30  import org.apache.logging.log4j.status.StatusLogger;
31  import org.mycore.common.MCRClassTools;
32  import org.mycore.common.MCRException;
33  
34  /**
35   * This class abstracts different MyCoRe component types.
36   * As every component (mycore component, application module) holds it configuration in different places,
37   * you can use this class to get uniform access to these configuration resources.
38   * 
39   * As this class is immutable it could be used as key in a {@link Map}
40   * @author Thomas Scheffler (yagee)
41   * @since 2013.12
42   * @see MCRRuntimeComponentDetector
43   */
44  public class MCRComponent implements Comparable<MCRComponent> {
45  
46      private static final Logger LOGGER = StatusLogger.getLogger();
47  
48      private static final String ATT_PRIORITY = "Priority";
49  
50      private static final NumberFormat PRIORITY_FORMAT = getPriorityFormat();
51  
52      private static NumberFormat getPriorityFormat() {
53          NumberFormat format = NumberFormat.getIntegerInstance(Locale.ROOT);
54          format.setGroupingUsed(false);
55          format.setMinimumIntegerDigits(3);
56          return format;
57      }
58  
59      private static final String DEFAULT_PRIORITY = "99";
60  
61      private enum Type {
62          base, component, module
63      }
64  
65      private Type type;
66  
67      private String name;
68  
69      private File jarFile;
70  
71      private String sortCriteria;
72  
73      private String artifactId;
74  
75      private Manifest manifest;
76  
77      public MCRComponent(String artifactId, Manifest manifest) {
78          this(artifactId, manifest, null);
79      }
80  
81      public MCRComponent(String artifactId, Manifest manifest, File jarFile) {
82          if (artifactId.startsWith("mycore-")) {
83              if (artifactId.endsWith("base")) {
84                  type = Type.base;
85                  setName("base");
86              } else {
87                  type = Type.component;
88                  setName(artifactId.substring("mycore-".length()));
89              }
90          } else {
91              type = Type.module;
92              setName(artifactId.replaceAll("[_-]?module", ""));
93          }
94          setJarFile(jarFile);
95          this.artifactId = artifactId;
96          this.manifest = manifest;
97          buildSortCriteria();
98          LOGGER.debug("{} is of type {} and named {}: {}", artifactId, type, getName(), jarFile);
99      }
100 
101     private void buildSortCriteria() {
102         String priorityAtt = manifest.getMainAttributes().getValue(ATT_PRIORITY);
103         if (priorityAtt == null) {
104             priorityAtt = DEFAULT_PRIORITY;
105             LOGGER.debug("{} has DEFAULT priority {}", artifactId, priorityAtt);
106         } else {
107             LOGGER.debug("{} has priority {}", artifactId, priorityAtt);
108         }
109         int priority = Integer.parseInt(priorityAtt);
110         if (priority > 99 || priority < 0) {
111             throw new MCRException(artifactId + " has unsupported priority: " + priority);
112         }
113         switch (type) {
114         case base:
115             priority += 100;
116             break;
117         case component:
118             priority += 200;
119             break;
120         case module:
121             priority += 300;
122             break;
123         default:
124             throw new MCRException("Do not support MCRComponenty of type: " + type);
125         }
126         this.sortCriteria = PRIORITY_FORMAT.format(priority) + getName();
127     }
128 
129     public InputStream getConfigFileStream(String filename) {
130         String resourceBase = getResourceBase();
131         if (resourceBase == null) {
132             return null;
133         }
134         String resourceName = resourceBase + filename;
135         InputStream resourceStream = MCRClassTools.getClassLoader().getResourceAsStream(resourceName);
136         if (resourceStream != null) {
137             LOGGER.info("Reading config resource: {}", resourceName);
138         }
139         return resourceStream;
140     }
141 
142     public URL getConfigURL(String filename) {
143         String resourceBase = getResourceBase();
144         if (resourceBase == null) {
145             return null;
146         }
147         String resourceName = resourceBase + filename;
148         URL resourceURL = MCRClassTools.getClassLoader().getResource(resourceName);
149         if (resourceURL != null) {
150             LOGGER.info("Reading config resource: {}", resourceName);
151         }
152         return resourceURL;
153     }
154 
155     /**
156      * Returns resource base path to this components config resources.
157      */
158     public String getResourceBase() {
159         switch (type) {
160         case base:
161             return "config/";
162         case component:
163             return "components/" + getName() + "/config/";
164         case module:
165             return "config/" + getName() + "/";
166         default:
167             LOGGER.debug("{}: there is no resource base for type {}", getName(), type);
168             break;
169         }
170         return null;
171     }
172 
173     /**
174      * Returns true, if this component is part of MyCoRe
175      */
176     public boolean isMyCoReComponent() {
177         return type == Type.base || type == Type.component;
178     }
179 
180     /**
181      * Returns true, if this component is application module 
182      */
183     public boolean isAppModule() {
184         return type == Type.module;
185     }
186 
187     /**
188      * A short name for this component.
189      * E.g. mycore-base would return "base" here.
190      */
191     public String getName() {
192         return name;
193     }
194 
195     private void setName(String name) {
196         this.name = name;
197     }
198 
199     /**
200      * Returns the jar file or <code>null</code> if nothing was set.
201      * 
202      * @return the jar file
203      */
204     public File getJarFile() {
205         return jarFile;
206     }
207 
208     private void setJarFile(File jarFile) {
209         this.jarFile = jarFile;
210     }
211 
212     /**
213      * Returns the mainfest main attribute value for given attribute name.
214      * 
215      * @param name the attribute name
216      * @return the attribute value
217      */
218     public String getManifestMainAttribute(String name) {
219         return manifest.getMainAttributes().getValue(name);
220     }
221 
222     /**
223      * Compares this component to other component.
224      * Basic order is:
225      * <ol>
226      *  <li>complete</li>
227      *  <li>base</li>
228      *  <li>component</li>
229      *  <li>module</li>
230      * </ol>
231      * If more than one component is in one of these groups, they are sorted alphabetically via {@link #getName()}.
232      */
233     @Override
234     public int compareTo(MCRComponent o) {
235         return this.sortCriteria.compareTo(o.sortCriteria);
236     }
237 
238     @Override
239     public int hashCode() {
240         final int prime = 31;
241         int result = 1;
242         result = prime * result + ((name == null) ? 0 : name.hashCode());
243         result = prime * result + ((type == null) ? 0 : type.hashCode());
244         return result;
245     }
246 
247     @Override
248     public boolean equals(Object obj) {
249         if (this == obj) {
250             return true;
251         }
252         if (obj == null) {
253             return false;
254         }
255         if (!(obj instanceof MCRComponent)) {
256             return false;
257         }
258         MCRComponent other = (MCRComponent) obj;
259         if (name == null) {
260             if (other.name != null) {
261                 return false;
262             }
263         } else if (!name.equals(other.name)) {
264             return false;
265         }
266         return type == other.type;
267     }
268 
269     @Override
270     public String toString() {
271         StringBuilder sb = new StringBuilder();
272         switch (type) {
273         case base:
274         case component:
275             sb.append("mcr:");
276             break;
277         case module:
278             sb.append("app:");
279             break;
280         default:
281             break;
282         }
283         sb.append(artifactId);
284         return sb.toString();
285     }
286 }